package com.echronos.finance.manager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.echronos.commons.Result;
import com.echronos.commons.enums.CommonResultCode;
import com.echronos.commons.enums.CommonStatus;
import com.echronos.commons.exception.BusinessException;
import com.echronos.commons.model.AppThreadLocal;
import com.echronos.commons.utils.CopyObjectUtils;
import com.echronos.finance.api.enums.CreditModeEnums;
import com.echronos.finance.api.req.AcquireReceiptOnlineReq;
import com.echronos.finance.api.req.OnlineSplitItemReq;
import com.echronos.finance.api.req.ReceiptOrderDetailReq;
import com.echronos.finance.api.req.ReceiptOrderQuickNotifyReq;
import com.echronos.finance.api.resp.ReceiptOnlineResp;
import com.echronos.finance.commons.AcquireReceiptOnlineHandler;
import com.echronos.finance.dao.AcquireReceiptOnlineStrategy;
import com.echronos.finance.dto.AccountingBatchDTO;
import com.echronos.finance.dto.AccountingBatchItemDTO;
import com.echronos.finance.dto.AccountingTrialAutomaticDTO;
import com.echronos.finance.dto.AccountingTrialItemDTO;
import com.echronos.finance.enums.*;
import com.echronos.finance.model.*;
import com.echronos.finance.param.BalanceItemStaveParam;
import com.echronos.finance.param.CostItemStaveParam;
import com.echronos.finance.service.*;
import com.echronos.finance.util.BigDecimalUtils;
import com.echronos.finance.util.NumberSequence;
import com.echronos.finance.util.RedisLock;
import com.echronos.nms.api.enums.NmsTemplateEnums;
import com.echronos.order.feign.IPayFeign;
import com.echronos.order.req.PayCallBackReq;
import com.echronos.order.req.PayDivideSkuReq;
import com.echronos.order.req.PaySubmitReq;
import com.echronos.order.req.SettleCreditPayReq;
import com.echronos.order.resp.DivideSkuDetailResp;
import com.echronos.order.resp.OrderPayResp;
import com.echronos.order.resp.PayDivideSkuResp;
import com.echronos.payment.api.feign.IPayAccountingClient;
import com.echronos.payment.api.feign.IPaySupportMchFeignClient;
import com.echronos.payment.api.req.SupportAccountingRuleMatchReq;
import com.echronos.payment.api.req.SupportAccountingSkuMatchReq;
import com.echronos.payment.api.req.SupportCpcnMchQueryReq;
import com.echronos.payment.api.resp.IPaySupportCpcnMchResp;
import com.echronos.payment.api.resp.SupportAccountingRulePartResp;
import com.echronos.payment.api.resp.SupportAccountingRuleResp;
import com.echronos.pms.resp.SkuListResp;
import com.echronos.system.feign.IPermissionFeign;
import com.echronos.system.resp.CompanyResp;
import com.echronos.system.resp.member.MemberSimpleResp;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.echronos.finance.enums.FinanceResultCode.FinanceResultEnum.*;

/**
 * @Author wangyadong
 * @Date 2023/9/14 10:37
 * @ClassName MallAcquireReceiptOnlineStrategy
 */
@Slf4j
@Service
@AcquireReceiptOnlineHandler(value = AcquireReceiptOnlineEnums.MALL_ORDER)
public class MallAcquireReceiptOnlineStrategy implements AcquireReceiptOnlineStrategy {
    @Resource
    private CompanyService companyService;
    @Resource
    private ReceiptOnlinePayManager receiptOnlinePayManager;
    @Resource
    private ReceiptOnlineManager receiptOnlineManager;
    @Resource
    private SettlementBatchManager settlementBatchManager;
    @Resource
    private SettlementDetailManager settlementDetailManager;
    @Resource
    private ReceiptOrderManager receiptOrderManager;
    @Resource
    private ReceiptOrderDetailManager receiptOrderDetailManager;
    @Resource
    private CreditRecordManager creditRecordManager;
    @Resource
    private IPayFeign iPayFeign;
    @Resource
    private CreditConfigureManager configureManager;
    @Resource
    private NmsMessagePushService messagePushService;
    @Resource
    private RedisLock redisLock;
    @Resource
    private IPermissionFeign permissionFeign;
    @Resource
    private CreditRepaymentManager repaymentManager;
    @Resource
    private CreditVoucherManager voucherManager;
    @Resource
    private CreditSettingManager settingManager;
    @Resource
    private CreditRepaymentItemManager repaymentItemManager;
    /**
     * 超时时间 2S
     */
    private final long lockOutTime = 2;
    @Resource
    private BalanceItemService balanceItemService;
    @Resource
    private AccountBalanceService balanceService;
    @Resource
    private CostItemService costItemService;
    @Resource
    private AccountingOnlineSplitManager splitManager;
    @Resource
    private AccountBalanceManager accountBalanceManager;
    @Resource
    private AccountingOnlineSplitCategoryManager splitCategoryManager;

    @Resource
    private PmsProductService pmsProductService;
    @Resource
    private CreditConfigureTemporaryQuotaManager quotaManager;
    @Resource
    private ReceiptOrderService receiptOrderService;
    @Resource
    private AccountingTrialItemManager trialItemManager;
    @Resource
    private AccountingBatchManager accountingBatchManager;
    @Resource
    private AccountingBatchItemManager batchItemManager;
    @Resource
    private PaymentAccountingService paymentAccountingService;
    @Resource
    private OrderFeignService orderFeignService;
    @Resource
    private AccountingTrialManager trialManager;
    @Resource
    private AccountingTrialPartManager trialPartManager;
    @Resource
    private IPaySupportMchFeignClient supportMchFeignClient;
    @Resource
    private IPayAccountingClient iPayAccountingClient;
    @Resource
    private AccountingSplitManager accountingSplitManager;
    @Resource
    private AccountingSplitItemManager accountingSplitItemManager;


    /**
     * 在线收单
     *
     * @param req
     * @return
     */
    @Override
    public ReceiptOnlineResp handleAcquireReceiptOnline(AcquireReceiptOnlineReq req) {
        Long startTime = System.currentTimeMillis();
        log.info("在线收单-请求参数-req：{}", JSON.toJSONString(req));
        List<Integer> payStatusList = Lists.newArrayList(ReceiptOrderDetailPayStatusEnums.PAY_WAIT.getCode(),
                ReceiptOrderDetailPayStatusEnums.PAY_REJECT.getCode());
        //根据付款单编号查询主收款单
        List<ReceiptOrder> receiptOrders = receiptOrderManager.list(new LambdaQueryWrapper<ReceiptOrder>()
                .eq(ReceiptOrder::getIsDeleted, false)
                .eq(ReceiptOrder::getPayCompanyId, req.getPayCompanyId())
                .eq(ReceiptOrder::getReceiptStatus, ReceiptStatusEnums.RECEIPT_PAYING.getCode())
                .in(ReceiptOrder::getPayNo, req.getOrderNos())
        );
        if (CollectionUtils.isEmpty(receiptOrders)) {
            log.info("acquireReceiptOnline receiptOrders is null");
            throw new BusinessException(RECEIPT_ORDER_DATA_IS_NOT_EXISTS.getCode(), RECEIPT_ORDER_DATA_IS_NOT_EXISTS.getMessage());
        }
        Map<String, Long> longMap = receiptOrders.stream().collect(Collectors.toMap(ReceiptOrder::getPayNo, r -> r.getId()));

        List<Integer> payCompanyIds = receiptOrders.stream().map(ReceiptOrder::getPayCompanyId).collect(Collectors.toList());
        List<Integer> receiptCompanyIds = receiptOrders.stream().map(ReceiptOrder::getReceiptCompanyId).collect(Collectors.toList());
        List<AccountBalance> accountBalances = accountBalanceManager.list(new LambdaQueryWrapper<AccountBalance>()
                .in(AccountBalance::getCompanyId, payCompanyIds)
                .in(AccountBalance::getUpCompanyId, receiptCompanyIds)
                .eq(AccountBalance::getAccountType, AccountTypeEnums.NORMALLY_ACCOUNT.getCode())
        );
        Map<String, AccountBalance> accountBalanceMap = accountBalances.stream().collect(Collectors.toMap(r ->
                r.getCompanyId() + "_" + r.getUpCompanyId(), r -> r));
        List<AccountBalance> addList = new ArrayList<>();
        List<String> accountKeyList = Lists.newArrayList();
        receiptOrders.stream().forEach(r -> {
            String key = r.getPayCompanyId() + "_" + r.getReceiptCompanyId();
            AccountBalance accountBalance = accountBalanceMap.get(key);
            if (ObjectUtils.isNull(accountBalance) && !accountKeyList.contains(key)) {
                accountBalance = new AccountBalance();
                accountBalance.setAccountNo(NumberSequence.getAccountNumber());
                accountBalance.setBalance(BigDecimal.ZERO);
                accountBalance.setAccountType(AccountTypeEnums.NORMALLY_ACCOUNT.getCode());
                accountBalance.setCompanyId(r.getPayCompanyId());
                accountBalance.setSourceCompanyId(r.getSourceCompanyId());
                accountBalance.setToCompanyId(r.getToCompanyId());
                accountBalance.setUpCompanyId(r.getReceiptCompanyId());
                accountBalance.setIsUse(true);
                accountBalance.setLockBalance(BigDecimal.ZERO);
                addList.add(accountBalance);
                accountKeyList.add(key);
            }
        });
        if (CollectionUtils.isNotEmpty(addList)) {
            accountBalanceManager.saveOrUpdateBatch(addList);
        }
        //查询出所有收款明细
        List<Long> ids = receiptOrders.stream().map(ReceiptOrder::getId).collect(Collectors.toList());
        List<SettlementDetail> settlementDetails = settlementDetailManager.list(new LambdaQueryWrapper<SettlementDetail>()
                .in(SettlementDetail::getReceiptId, ids)
        );
        if (CollectionUtils.isNotEmpty(settlementDetails)) {
            List<Long> batchIds = settlementDetails.stream().map(SettlementDetail::getSettlementId).collect(Collectors.toList());
            List<SettlementBatch> batches = settlementBatchManager.list(new LambdaQueryWrapper<SettlementBatch>()
                    .in(SettlementBatch::getId, batchIds)
                    .eq(SettlementBatch::getIsDeleted, false)
            );
            if (CollectionUtils.isNotEmpty(batches)) {
                throw new BusinessException(20008, "已创建结算付款单，无法单独支付款项！");
            }
        }
        //查询出所有收款明细
        List<Long> idList = receiptOrders.stream().map(ReceiptOrder::getId).collect(Collectors.toList());
        List<ReceiptOrderDetail> rodList = receiptOrderDetailManager.list(new LambdaQueryWrapper<ReceiptOrderDetail>()
                .in(ReceiptOrderDetail::getReceiptId, idList)
                .in(ReceiptOrderDetail::getPayStatus, payStatusList)
                .eq(ReceiptOrderDetail::getIsDeleted, false)
                .eq(ReceiptOrderDetail::getIsCancel, false)
        );
        log.info("查询出所有收款明细：payNo:{},rodList:{},", JSON.toJSONString(req.getOrderNos()), JSON.toJSONString(rodList));
        if (CollectionUtils.isEmpty(rodList)) {
            log.info("acquireReceiptOnline rodList is null");
            throw new BusinessException(RECEIPT_HAD_BEEN_PAID.getCode(), RECEIPT_HAD_BEEN_PAID.getMessage());
        }
        Map<Long, ReceiptOrderDetail> receiptOrderDetailMap = rodList.stream().collect(Collectors.toMap(ReceiptOrderDetail::getReceiptId, r -> r));

        List<PayDivideSkuReq> reqList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(req.getSplitItemList())) {
            req.getSplitItemList().stream().forEach(r -> {
                PayDivideSkuReq skuReq = CopyObjectUtils.copyAtoB(r, PayDivideSkuReq.class);
                skuReq.setPayAmount(r.getAmount());
                reqList.add(skuReq);
            });
        } else if (CollectionUtils.isNotEmpty(req.getOrderNos())) {
            req.getOrderNos().stream().forEach(r -> {
                PayDivideSkuReq skuReq = new PayDivideSkuReq();
                skuReq.setPayNo(r);
                if (ObjectUtils.isNull(req.getAmount()) || req.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
                    Long aLong = longMap.get(r);
                    if (ObjectUtils.isNotNull(aLong)) {
                        ReceiptOrderDetail detail = receiptOrderDetailMap.get(aLong);
                        if (ObjectUtils.isNotNull(detail)) {
                            skuReq.setPayAmount(detail.getReceiveAmount());
                        }
                    }
                } else {
                    skuReq.setPayAmount(req.getAmount());
                }
                reqList.add(skuReq);
            });
        }
        Result<List<PayDivideSkuResp>> listResult = iPayFeign.payDivideSkuAmount(reqList);
        if (listResult.getCode() != 0) {
            log.error("【平台业务操作失败】查询订单款项支付金额明细异常error：{}", listResult.getMessage());
            throw new BusinessException(51200, "查询订单款项支付金额明细异常");
        }
        //同步付款单金额
        Result result = syncBatchOrderPayNoAmount(rodList, receiptOrders);
        if (result.getCode() != 0) {
            throw new BusinessException(RECEIPT_SYNC_PAYNO_AMOUNT_EXCEPTION.getCode(), result.getMessage());
        }
        //是否有赊销信息
        List<CreditRecord> list = creditRecordManager.list(new LambdaQueryWrapper<CreditRecord>()
                .in(CreditRecord::getReceiptId, ids)
                .eq(CreditRecord::getIsReject, false));
        //是否存在赊销单主单未收款
        if (CollectionUtils.isNotEmpty(list)) {
            List<Integer> orders = receiptOrders.stream().map(ReceiptOrder::getPayId).collect(Collectors.toList());
            List<ReceiptOrder> receipts = receiptOrderManager.list(new LambdaQueryWrapper<ReceiptOrder>()
                    .notIn(ReceiptOrder::getId, ids)
                    .in(ReceiptOrder::getPayId, orders)
                    .eq(ReceiptOrder::getIsDeleted, Boolean.FALSE)
                    .eq(ReceiptOrder::getReceiptStatus, ReceiptStatusEnums.RECEIPT_PAYING.getCode())
            );
            if (CollectionUtils.isNotEmpty(receipts)) {
                throw new BusinessException(RECEIPT_CREDIT_CANT_PAY.getCode(), RECEIPT_CREDIT_CANT_PAY.getMessage());
            }
            List<ReceiptOrderDetail> details = receiptOrderDetailManager.list(new LambdaQueryWrapper<ReceiptOrderDetail>()
                    .in(ReceiptOrderDetail::getReceiptId, ids)
                    .eq(ReceiptOrderDetail::getIsReject, false)
                    .eq(ReceiptOrderDetail::getIsDeleted, false)
                    .eq(ReceiptOrderDetail::getPayStatus, ReceiptOrderDetailPayStatusEnums.PAY_CONFIRM.getCode())
            );
            if (CollectionUtils.isNotEmpty(details)) {
                throw new BusinessException(RECEIPT_CREDIT_CANT_PAY.getCode(), RECEIPT_CREDIT_CANT_PAY.getMessage());
            }
        }
        //存在未付利息和未付违约金的要去支付
        List<ReceiptOrderDetail> details = receiptOrderDetailManager.list(new LambdaQueryWrapper<ReceiptOrderDetail>()
                .in(ReceiptOrderDetail::getReceiptId, ids)
                .eq(ReceiptOrderDetail::getIsDeleted, false)
                .eq(ReceiptOrderDetail::getIsCancel, false)
        );
        //未付部分
        BigDecimal unPay = details.stream().map(r -> r.getUnPayBreak().add(r.getUnPayInterest())).reduce(BigDecimal.ZERO, BigDecimal::add);
        Map<Long, CreditRecord> recordMap = list.stream().collect(Collectors.toMap(CreditRecord::getReceiptId, r -> r));
        log.info("获取赊销记录：{}", list);
        //批量收款不支持赊销单收款
        if (CollectionUtils.isNotEmpty(list) && req.getOrderNos().size() > 1) {
            throw new BusinessException(RECEIPT_ORDER_CANT_BATCH.getCode(), RECEIPT_ORDER_CANT_BATCH.getMessage());
        }
        String MainOrderNo = receiptOrders.stream().map(ReceiptOrder::getMainOrderNo).distinct().collect(Collectors.joining(","));
        Integer orderType = receiptOrders.get(0).getOrderType();
        BigDecimal fundsAmount = rodList.stream().map(ReceiptOrderDetail::getFundsAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal receiveAmount = rodList.stream().map(ReceiptOrderDetail::getReceiveAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        receiveAmount = receiveAmount.add(unPay);
        String payName = rodList.stream().map(ReceiptOrderDetail::getPayName).findFirst().get();
        BigDecimal extraAmount = unPay;

        boolean isCredit = details.size() > 1 ? true : false;
        boolean isBreak = false;
        //存在赊销数据，则计算出对应赊销利息和赊销违约金
        if (CollectionUtils.isNotEmpty(list)) {
            ArrayList<ReceiptOrderDetail> receiptOrderDetails = new ArrayList<>();
            for (ReceiptOrderDetail detail : rodList) {
                CreditRecord creditRecord = recordMap.get(detail.getReceiptId());
                log.info("在线收单-获取赊销记录：{}", creditRecord);
                if (detail.getIsCredit() && creditRecord != null) {
                    BigDecimal creditAmount = creditRecord.getCreditAmount();
                    log.info("在线收单-赊销金额：{}", creditAmount);
                    //计算利息
                    BigDecimal interestAmount = creditRecordManager.calculateInterestAmount(creditRecord, detail.getPayTime());
                    log.info("在线收单-利息：{}", interestAmount);
                    //计算违约金
                    BigDecimal breakAmount = creditRecordManager.calculateBreakAmount(creditRecord, interestAmount, detail.getPayTime());
                    log.info("在线收单-违约金：{}", breakAmount);
                    //校验是否违约，产生违约则更新违约已使用额度
                    isBreak = creditRecordManager.checkIsBreak(creditRecord, detail.getReceiptId(), detail.getPayTime());
                    //应付总金额
                    receiveAmount = receiveAmount.add(interestAmount).add(breakAmount);
                    detail.setBreakAmount(breakAmount);
                    detail.setInterestAmount(interestAmount);
                    detail.setFundsAmount(fundsAmount);
                    detail.setReceiveAmount(BigDecimalUtils.amountScale(receiveAmount));
                    detail.setUpdateTime(LocalDateTime.now());
                    receiptOrderDetails.add(detail);
                    extraAmount = extraAmount.add(interestAmount).add(breakAmount);
                    log.info("在线收单-应收总金额：{}", receiveAmount);
                    isCredit = true;
                }
            }
            receiptOrderDetailManager.saveOrUpdateBatch(receiptOrderDetails);
        }
        BigDecimal payment = ObjectUtils.isNull(req.getAmount()) || req.getAmount().compareTo(BigDecimal.ZERO) <= 0 ?
                receiveAmount : req.getAmount();
        if (ObjectUtils.isNotNull(req.getAmount()) && req.getAmount().compareTo(BigDecimal.ZERO) > 0) {
            if (req.getAmount().compareTo(receiveAmount) > 0) {
                throw new BusinessException(50000, "支付金额超出款项应付金额，确认后重试！");
            }
        }
        List<Integer> companyIds = receiptOrders.stream().map(ReceiptOrder::getReceiptCompanyId).collect(Collectors.toList());
        //生成收款记录 ，汇总金额
        ReceiptOnline receiptOnline = new ReceiptOnline();
        receiptOnline.setTitle(payName);
        receiptOnline.setPayAmount(payment);
        receiptOnline.setAmount(receiveAmount);
        receiptOnline.setFundAmount(fundsAmount);
        receiptOnline.setProductAmount(fundsAmount);
        receiptOnline.setOrderNo(MainOrderNo);
        receiptOnline.setCreateTime(LocalDateTime.now());
        receiptOnline.setOrderType(orderType);
        receiptOnline.setToCompanyId(receiptOrders.get(0).getToCompanyId());
        receiptOnline.setPayOrderNo(NumberSequence.getReceiptOnlineNumber());
        receiptOnline.setPayCompanyId(receiptOrders.get(0).getPayCompanyId());
        receiptOnline.setToCompanyName(receiptOrders.get(0).getToCompanyName());
        receiptOnline.setPayCompanyName(receiptOrders.get(0).getPayCompanyName());
        receiptOnline.setSourceCompanyId(receiptOrders.get(0).getSourceCompanyId());
        receiptOnline.setReceiptCompanyId(receiptOrders.get(0).getReceiptCompanyId());
        receiptOnline.setOnlineResult(ReceiptOnlineResultEnums.UN_COMPLETED.getCode());
        receiptOnline.setSourceCompanyName(receiptOrders.get(0).getSourceCompanyName());
        receiptOnline.setReceiptCompanyName(receiptOrders.get(0).getReceiptCompanyName());
        receiptOnlineManager.save(receiptOnline);
        Map<String, OnlineSplitItemReq> splitItemReqMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(req.getSplitItemList())) {
            splitItemReqMap.putAll(req.getSplitItemList().stream().collect(Collectors.toMap(OnlineSplitItemReq::getPayNo, r -> r)));
        }
        List<PayDivideSkuResp> skuResps = listResult.getData();
        List<Integer> skuIds = new ArrayList<>();
        skuResps.stream().forEach(r -> {
            skuIds.addAll(r.getSkuDetailList().stream().map(DivideSkuDetailResp::getSkuId).collect(Collectors.toList()));
        });
        Map<Integer, SkuListResp> skuByIds = new HashMap<>();
        if (CollectionUtils.isNotEmpty(skuIds)) {
            skuByIds.putAll(pmsProductService.findSkuByIds(skuIds));
        }
        Map<String, PayDivideSkuResp> skuRespMap = skuResps.stream().collect(Collectors.toMap(PayDivideSkuResp::getPayNo, r -> r));
        Map<Long, ReceiptOrder> orderMap = receiptOrders.stream().collect(Collectors.toMap(ReceiptOrder::getId, r -> r));
        //生成分账记录
        //生成收款记录和收款单 的中间表数据
        ArrayList<ReceiptOnlinePay> onlinePays = new ArrayList<>();
        rodList.stream().forEach(r -> {
            ReceiptOnlinePay onlinePay = new ReceiptOnlinePay();
            onlinePay.setReceiptOnlineId(receiptOnline.getId());
            onlinePay.setReceiptId(r.getReceiptId());
            onlinePay.setCreateTime(LocalDateTime.now());
            onlinePays.add(onlinePay);
            ReceiptOrder order = orderMap.get(r.getReceiptId());
            PayDivideSkuResp payDivideSkuResp = skuRespMap.get(order.getPayNo());
            OnlineSplit split = new OnlineSplit();
            split.setOnlineId(receiptOnline.getId());
            split.setReceiptId(order.getId());
            split.setFundsAmount(order.getOrderAmount());
            split.setPayNo(order.getPayNo());
            split.setAmount(ObjectUtils.isNull(payDivideSkuResp) ? req.getAmount() : payDivideSkuResp.getSkuDetailList()
                    .stream().map(DivideSkuDetailResp::getDivideAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
            split.setItemNo(NumberSequence.getSplitNO());
            split.setGroupOrderId(payDivideSkuResp.getGroupOrderId());
            split.setDiscount(payDivideSkuResp.getIfDiscount());
            split.setOrderNo(order.getOrderNo());
            splitManager.saveOrUpdate(split);
            if (ObjectUtils.isNotNull(payDivideSkuResp) && CollectionUtils.isNotEmpty(payDivideSkuResp.getSkuDetailList())) {
                payDivideSkuResp.getSkuDetailList().stream().forEach(t -> {
                    OnlineSplitCategory splitCategory = CopyObjectUtils.copyAtoB(t, OnlineSplitCategory.class);
                    splitCategory.setOnlineId(receiptOnline.getId());
                    splitCategory.setReceiptId(order.getId());
                    splitCategory.setItemId(split.getId());
                    splitCategory.setAmount(t.getDivideAmount());
                    SkuListResp skuListResp = skuByIds.get(t.getSkuId());
                    if (ObjectUtils.isNotNull(skuListResp)) {
                        splitCategory.setCategoryId(skuListResp.getCategoryId());
                    }
                    splitCategoryManager.saveOrUpdate(splitCategory);
                });
            }
        });
        receiptOnlinePayManager.saveOrUpdateBatch(onlinePays);
        //返回收银台数据
        ReceiptOnlineResp receiptOnlineResp = CopyObjectUtils.copyAtoB(receiptOnline, ReceiptOnlineResp.class);
        receiptOnlineResp.setIsBreak(isBreak);
        receiptOnlineResp.setIsCredit(isCredit);
        receiptOnlineResp.setBankNo(receiptOrders.get(0).getBankNo());
        receiptOnlineResp.setBankName(receiptOrders.get(0).getBankName());
        receiptOnlineResp.setOrderType(orderType);
        receiptOnlineResp.setToCompanyId(receiptOrders.get(0).getToCompanyId());
        receiptOnlineResp.setExtraAmount(BigDecimalUtils.amountScale(extraAmount));
        receiptOnlineResp.setToCompanyName(receiptOrders.get(0).getToCompanyName());
        receiptOnlineResp.setSourceCompanyId(receiptOrders.get(0).getSourceCompanyId());
        receiptOnlineResp.setReceiptCompanyId(receiptOrders.get(0).getReceiptCompanyId());
        receiptOnlineResp.setSourceCompanyName(receiptOrders.get(0).getSourceCompanyName());
        receiptOnlineResp.setReceiptCompanyName(receiptOrders.get(0).getReceiptCompanyName());
        receiptOnlineResp.setPayAmount(BigDecimalUtils.amountScale(receiptOnlineResp.getPayAmount()));
        receiptOnlineResp.setReceiptCompanyIds(companyIds);
        Long endTime = System.currentTimeMillis();
        Long tempTime = (endTime - startTime);
        log.info("在线收单-返回收银台数据-耗时: {} ms ,{}", tempTime, receiptOnlineResp);
        return receiptOnlineResp;
    }

    @Override
    public ReceiptOnlineResp queryReceiptOnline(ReceiptOnline receiptOnline) {
        List<Long> receiptOnlineIds = Lists.newArrayList(receiptOnline.getId());
        //获取收款记录对应-收款单下所有的明细
        receiptOnlineIds.add(receiptOnline.getId());
        List<ReceiptOrderDetail> rodList = receiptOrderDetailManager.findReceiptOnlines(receiptOnlineIds);
        if (CollectionUtils.isEmpty(rodList)) {
            log.info("queryReceiptOnline rodList is null");
            throw new BusinessException(RECEIPT_ONLINE_PAY_DATA_IS_NULL.getCode(), RECEIPT_ONLINE_PAY_DATA_IS_NULL.getMessage());
        }
        log.info("获取收款记录对应-收款单下所有的明细：{}", rodList);
        boolean flag = false;
        for (ReceiptOrderDetail rod : rodList) {
            //有支付成功的明细单，则返回异常
            if (rod.getPayStatus().equals(ReceiptOrderDetailPayStatusEnums.PAY_SUCCESS.getCode())) {
                flag = true;
                break;
            }
        }
        if (flag) {
            throw new BusinessException(RECEIPT_EXISTS_SUCCESS_RECORD_ERROR.getCode(), RECEIPT_EXISTS_SUCCESS_RECORD_ERROR.getMessage());
        }
        List<ReceiptOrder> orders = receiptOrderManager.listByIds(rodList.stream().map(ReceiptOrderDetail::getReceiptId)
                .collect(Collectors.toList()));
        String payNo = orders.stream().map(ReceiptOrder::getPayNo).collect(Collectors.joining(","));
        ReceiptOnlineResp receiptOnlineResp = CopyObjectUtils.copyAtoB(receiptOnline, ReceiptOnlineResp.class);
        receiptOnlineResp.setPayNo(payNo);
        log.info("查询收款记录-操作成功");
        return receiptOnlineResp;
    }

    /**
     * 同步付款单金额
     */
    public Result syncBatchOrderPayNoAmount(List<ReceiptOrderDetail> details, List<ReceiptOrder> orders) {
        List<String> payNoList = orders.stream().map(ReceiptOrder::getPayNo).collect(Collectors.toList());
        Map<Long, ReceiptOrder> orderMap = orders.stream().collect(Collectors.toMap(ReceiptOrder::getId, r -> r));
        log.info("syncBatchOrderPayNoAmount 请求参数payNoList：{}", JSON.toJSONString(payNoList));
        Result<Map<String, OrderPayResp>> mapResult = iPayFeign.queryOrderPayInfoMap(payNoList);
        log.info("syncOrderPayNoAmount result：{}", JSONObject.toJSONString(mapResult));
        if (!mapResult.isSuccess()) {
            throw new BusinessException(RECEIPT_SYNC_PAYNO_AMOUNT_EXCEPTION.getCode(), mapResult.getMessage());
        }
        Map<String, OrderPayResp> data = mapResult.getData();
        for (ReceiptOrderDetail rod : details) {
            ReceiptOrder order = orderMap.get(rod.getReceiptId());
            if (ObjectUtils.isNull(order)) {
                continue;
            }
            OrderPayResp orderPayResp = data.get(order.getPayNo());
            BigDecimal payPrice = ObjectUtils.isNull(orderPayResp.getPayPrice()) ? BigDecimal.ZERO : orderPayResp.getPayPrice();
            BigDecimal receiveAmount = rod.getReceiveAmount();
            //金额不一致，以订单返回的金额为准
            if (payPrice.compareTo(receiveAmount) != 0) {
                rod.setReceiveAmount(payPrice);
                rod.setFundsAmount(payPrice);
                receiptOrderDetailManager.updateById(rod);
                order.setOrderAmount(payPrice);
                order.setShouldAmount(payPrice);
            }
            Integer sourceCompanyId = orderPayResp.getSourceCompanyId();
            Integer toCompanyId = orderPayResp.getToCompanyId();
            if (ObjectUtils.isNotEmpty(sourceCompanyId) && sourceCompanyId != 0) {
                order.setSourceCompanyId(orderPayResp.getSourceCompanyId());
                order.setSourceCompanyName(orderPayResp.getSourceCompanyName());
            }
            if (ObjectUtils.isNotEmpty(toCompanyId) && toCompanyId != 0) {
                order.setToCompanyId(orderPayResp.getToCompanyId());
                order.setToCompanyName(orderPayResp.getToCompanyName());
            }
            receiptOrderManager.updateById(order);
        }
        return Result.build();
    }

    @Override
    public void offlineUpdateReceiptOrderDetail(ReceiptOrderDetailReq rodReq, ReceiptOnline online) {
        try {
            //根据收款记录编号查询对应的明细
            //不支持快捷支付方式回显
            String payMode = rodReq.getPayMode();
            List<ReceiptOrderDetail> rodList = receiptOrderDetailManager.findReceiptOrderDetailByPayOrderNo(rodReq.getPayOrderNo());
            if (CollectionUtils.isEmpty(rodList)) {
                throw new BusinessException(RECEIPT_ORDER_DETAIL_IS_NOT_EXISTS.getCode(), RECEIPT_ORDER_DETAIL_IS_NOT_EXISTS.getMessage());
            }
            log.info("查询对应的明细：payOrderNo:{},rodList:{}", rodReq.getPayOrderNo(), rodList);
            if (rodList.size() > 1) {
                throw new BusinessException(RECEIPT_ORDER_CANT_BATCH.getCode(), RECEIPT_ORDER_CANT_BATCH.getMessage());
            }
            BigDecimal payment = rodReq.getBalancePayAmount().add(rodReq.getPayAmount());
            ReceiptOrderDetail detail = rodList.get(0);
            ReceiptOrder order = receiptOrderManager.getOne(new LambdaQueryWrapper<ReceiptOrder>()
                    .eq(ReceiptOrder::getId, detail.getReceiptId())
                    .eq(ReceiptOrder::getIsDeleted, false)
                    .ne(ReceiptOrder::getReceiptStatus, ReceiptStatusEnums.RECEIPT_FAIL.getCode())
            );
            if (rodReq.getPayWay().equals(ReceiptOrderPayWayEnums.CREDIT.getCode()) &&
                    rodReq.getCreditMode().equals(CreditModeEnums.CREDIT_CYCLE.getCode())) {
                CreditConfigure creditConfigure = configureManager.getCreditConfigureByCompanyId(order.getReceiptCompanyId(),
                        order.getPayCompanyId());
                if (ObjectUtils.isNull(creditConfigure)) {
                    throw new BusinessException(20003, "无设置赊销信息，无法赊销支付！");
                }
                if (creditConfigure.getStatus().equals(CommonStatus.YesOrNoEnum.NO.getValue())) {
                    throw new BusinessException(20003, "赊销设置禁用状态，无法赊销支付！");
                }
                String creditLock = new StringBuilder().append(BusinessPrefixEnums.CREDIT_LOCK.getCode())
                        .append(creditConfigure.getId()).toString();
                if (!redisLock.getLock(creditLock, lockOutTime, TimeUnit.SECONDS)) {
                    throw new BusinessException(20001, "赊销额度计算中，请稍后重新提交！");
                }
                //判断是否存在财务款项id一样的数据
                List<CreditRepaymentItem> items = repaymentItemManager.list(new LambdaQueryWrapper<CreditRepaymentItem>()
                        .eq(CreditRepaymentItem::getReceiptId, order.getId())
                );
                if (ObjectUtils.isNotNull(items)) {
                    throw new BusinessException(60001, "订单已经使用赊销，请确认后重试！");
                }
                //所有未还款账单内容
                List<CreditRepayment> unPaymentList = repaymentManager.list(new LambdaQueryWrapper<CreditRepayment>()
                        .eq(CreditRepayment::getConfigureId, creditConfigure.getId())
                        .eq(CreditRepayment::getRepaymentStatus, RepaymentStatusEnums.UN_COMPLETE.getCode())
                );
                BigDecimal unPayFundsAmount = BigDecimal.ZERO;
                if (CollectionUtils.isNotEmpty(unPaymentList)) {
                    unPayFundsAmount = unPaymentList.stream().map(r -> r.getCreditAmount().subtract(r.
                            getPayFundsAmount()).subtract(r.getOffsetAmount())).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                BigDecimal leaveCreditLimit = creditConfigure.getCreditLimit().multiply(BigDecimal.valueOf(10000))
                        .subtract(unPayFundsAmount);
                CreditConfigureTemporaryQuota quota = quotaManager.getOne(new LambdaQueryWrapper<CreditConfigureTemporaryQuota>()
                        .eq(CreditConfigureTemporaryQuota::getCreditId, creditConfigure.getId())
                        .eq(CreditConfigureTemporaryQuota::getEffectiveStatus, CommonStatus.YesOrNoEnum.YES.getValue())
                );
                if (ObjectUtils.isNotNull(quota)) {
                    leaveCreditLimit = leaveCreditLimit.add(quota.getQuotaLimit().multiply(BigDecimal.valueOf(10000)));
                }
                if (order.getOrderAmount().compareTo(leaveCreditLimit) > 0) {
                    throw new BusinessException(30004, "赊销额度不足，请确认后重试！");
                }
                detail.setIsCredit(true);
                detail.setPayName(detail.getPayName() + "-全额赊销");
                detail.setCreditAmount(detail.getFundsAmount());
                receiptOrderDetailManager.saveOrUpdate(detail);
                CreditVoucher voucher = new CreditVoucher();
                voucher.setReceiptId(order.getId());
                voucher.setCreditAmount(order.getOrderAmount());
                voucher.setConfigureId(creditConfigure.getId());
                voucher.setPayCompanyId(order.getPayCompanyId());
                voucher.setReceiptCompanyId(order.getReceiptCompanyId());
                voucher.setInterestRate(creditConfigure.getInterestRate());
                voucherManager.saveOrUpdate(voucher);
                int dayOfMonth = LocalDateTime.now().plusHours(8L).getDayOfMonth();
                //区分是出账日内下单
                LocalDate accountDate = LocalDateTime.now().plusHours(8L).withDayOfMonth(creditConfigure.getAccountsDay())
                        .toLocalDate();
                if (creditConfigure.getAccountsDay() < dayOfMonth) {
                    //区分是出账日已过外下单
                    accountDate = LocalDateTime.now().plusHours(8L).plusMonths(1).withDayOfMonth(
                            creditConfigure.getAccountsDay()).toLocalDate();
                }
                //判断还款日在哪一区间日期点
                LocalDate repaymentDate = LocalDateTime.now().plusHours(8L).withDayOfMonth(
                        creditConfigure.getRepaymentDay()).toLocalDate();
                if (dayOfMonth > creditConfigure.getRepaymentDay() || accountDate.compareTo(repaymentDate) > 0) {
                    repaymentDate = LocalDateTime.now().plusHours(8L).plusMonths(1)
                            .withDayOfMonth(creditConfigure.getRepaymentDay()).toLocalDate();
                }
                LocalDate startDate = accountDate.minusMonths(1).plusDays(1);
                //是否已存在当前日期内的未出账单
                CreditRepayment repayment = repaymentManager.getOne(new LambdaQueryWrapper<CreditRepayment>()
                        .eq(CreditRepayment::getConfigureId, creditConfigure.getId())
                        .eq(CreditRepayment::getPayCompanyId, order.getPayCompanyId())
                        .eq(CreditRepayment::getEndDate, accountDate)
                        .eq(CreditRepayment::getReceiptCompanyId, order.getReceiptCompanyId())
                        .eq(CreditRepayment::getIsIssued, CommonStatus.YesOrNoEnum.NO.getValue())
                        .eq(CreditRepayment::getRepaymentStatus, CommonStatus.YesOrNoEnum.NO.getValue())
                );
                //创建一条待出账账单
                if (ObjectUtils.isNull(repayment)) {
                    repayment = new CreditRepayment();
                    repayment.setConfigureId(creditConfigure.getId());
                    repayment.setPayCompanyId(order.getPayCompanyId());
                    repayment.setReceiptCompanyId(order.getReceiptCompanyId());
                    repayment.setRepaymentStatus(RepaymentStatusEnums.UN_COMPLETE.getCode());
                    repayment.setIsIssued(Boolean.FALSE);
                    repayment.setInterestRate(creditConfigure.getInterestRate());
                    repayment.setStartDate(startDate);
                    repayment.setEndDate(accountDate);
                    repayment.setRepaymentNo(NumberSequence.getRepaymentNO());
                    repayment.setTenantId(AppThreadLocal.getTenantId());
                    repayment.setRepaymentDate(repaymentDate);
                    repayment.setCreditMode(creditConfigure.getCreditMode());
                    repayment.setShouldPayAmount(BigDecimal.ZERO);
                    repayment.setShouldReceiveAmount(BigDecimal.ZERO);
                    repayment.setCreditAmount(BigDecimal.ZERO);
                    repayment.setFundsAmount(BigDecimal.ZERO);
                    repaymentManager.saveOrUpdate(repayment);
                }
                repayment.setFundsAmount(repayment.getFundsAmount().add(order.getOrderAmount()));
                repayment.setCreditAmount(repayment.getCreditAmount().add(order.getOrderAmount()));
                repayment.setShouldPayAmount(repayment.getShouldPayAmount().add(order.getOrderAmount()));
                repayment.setShouldReceiveAmount(repayment.getShouldReceiveAmount().add(order.getOrderAmount()));
                repaymentManager.saveOrUpdate(repayment);
                CreditRepaymentItem item = new CreditRepaymentItem();
                item.setReceiptId(order.getId());
                item.setReceiptCreateTime(order.getCreateTime());
                item.setCreditAmount(order.getOrderAmount());
                item.setRepaymentId(repayment.getId());
                repaymentItemManager.saveOrUpdate(item);
                //释放锁
                redisLock.unlock(creditLock, String.valueOf(lockOutTime));
                Long beginTime = System.currentTimeMillis();
                SettleCreditPayReq paySubmitReq = new SettleCreditPayReq();
                paySubmitReq.setPayNo(order.getPayNo());
                paySubmitReq.setPayMember(rodReq.getMemberId());
                paySubmitReq.setPayTime(LocalDateTime.now());
                log.info("确定支付orderPaySubmit-请求参数:{}", JSON.toJSONString(paySubmitReq));
                Result<?> payRespResult = iPayFeign.settleCreditPaySubmit(paySubmitReq);
                Long endTime = System.currentTimeMillis();
                Long tempTime = (endTime - beginTime);
                log.info("确定支付orderPaySubmit响应-payNo:{},耗时:{} ms, Result:{}", order.getPayNo(), tempTime,
                        JSONObject.toJSONString(payRespResult));
                return;
            }
            BigDecimal divide = detail.getReceiveAmount().subtract(payment);
            if (BigDecimalUtils.amountScale(divide).compareTo(BigDecimal.ZERO) > 0
                    && !ReceiptOrderPayModeEnum.CREDIT.getCode().equals(payMode)) {
                //1.付款金额P小于本金F，则剩余部分为(F-P,I,B)
                //本金F比较付款金额P,剩余部分本金
                BigDecimal leaveFundsAmount = detail.getFundsAmount().subtract(payment);
                CreditRecord record = creditRecordManager.getOne(new LambdaQueryWrapper<CreditRecord>()
                        .eq(CreditRecord::getReceiptId, detail.getReceiptId()));
                //赊销部分支付,需支付金额包含（本金F、利息I、违约金B）
                //计算部分支付产生的利息
                BigDecimal unPayInterest = BigDecimal.ZERO;
                //计算部分支付产生的违约金
                BigDecimal unPayBreak = BigDecimal.ZERO;
                Boolean isCredit = Boolean.FALSE;
                //付款金额P
                if (ObjectUtils.isNotNull(record)) {
                    isCredit = Boolean.TRUE;
                    if (leaveFundsAmount.compareTo(BigDecimal.ZERO) > 0) {
                        record.setCreditAmount(payment);
                        unPayInterest = creditRecordManager.calculateInterestAmount(record, detail.getPayTime());
                        log.info("计算部分支付产生的利息-利息：{}", unPayInterest);
                        unPayBreak = creditRecordManager.calculateBreakAmount(record, unPayInterest, detail.getPayTime());
                        log.info("计算部分支付产生的违约金-违约金：{}", unPayBreak);
                        divide = leaveFundsAmount;
                    } else {
                        throw new BusinessException(RECEIPT_CREDIT_CANT_RULE.getCode(), RECEIPT_CREDIT_CANT_RULE.getMessage());
                    }
                    //更新当前赊销单计费本金为剩余未付
                    record.setCreditAmount(leaveFundsAmount);
                    creditRecordManager.saveOrUpdate(record);
                    //  违约金利息不做处理
                }
                detail.setCreditAmount(isCredit ? payment : BigDecimal.ZERO);
                detail.setUnPayBreak(unPayBreak);
                detail.setUnPayInterest(unPayInterest);
                detail.setBreakAmount(BigDecimal.ZERO);
                detail.setInterestAmount(BigDecimal.ZERO);
                detail.setPayUserId(rodReq.getPayUserId());
                receiptOrderDetailManager.saveOrUpdate(detail);
                //部分支付
                ReceiptOrderDetail orderDetail = new ReceiptOrderDetail();
                orderDetail.setIsCredit(isCredit);
                orderDetail.setFundsAmount(divide);
                orderDetail.setReceiveAmount(divide);
                orderDetail.setLinkId(detail.getLinkId());
                orderDetail.setPayName(detail.getPayName());
                orderDetail.setCreateTime(LocalDateTime.now());
                orderDetail.setReceiptId(detail.getReceiptId());
                orderDetail.setCreditDays(isCredit ? record.getCreditDays() : null);
                orderDetail.setCreditAmount(isCredit ? leaveFundsAmount : BigDecimal.ZERO);
                orderDetail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_WAIT.getCode());
                receiptOrderDetailManager.saveOrUpdate(orderDetail);
            }
            detail.setOrderRemark(rodReq.getRemark());
            //赊销支付模式
            if (ReceiptOrderPayModeEnum.CREDIT.getCode().equalsIgnoreCase(payMode)) {
                creditReceiptHandler(rodReq, detail);
            }
            // 线下转账模式
            if (ReceiptOrderPayModeEnum.OFFLINE_TRANSFER.getCode().equalsIgnoreCase(payMode)) {
                offlineTransReceiptHandler(rodReq, detail);
            }
            //余额支付模式
            if (ReceiptOrderPayModeEnum.WALLET.getCode().equalsIgnoreCase(payMode)) {
                walletReceiptHandler(rodReq, detail);
            }
            //组合支付模式
            if (ReceiptOrderPayModeEnum.GROUP.getCode().equalsIgnoreCase(payMode)) {
                groupReceiptHandler(rodReq, detail);
            }
            //超时违约金大于0，则更新违约已使用额度
            updateBreakUseAmount(detail);
            //将收款记录表online_result状态更新为已完成
            receiptOnlineManager.updateReceiptOnlineStatus(rodReq.getPayOrderNo(), rodReq.getPayTradeNo());
            Result<List<MemberSimpleResp>> listResult = permissionFeign.queryMemberInfoBy(order.getReceiptCompanyId(), "E_001_001_001_002");
            log.info("获取收款方公司成员信息members：{}", listResult.getCode());
            if (listResult.isSuccess() && ObjectUtils.isNotNull(listResult.getData())) {
                List<Integer> userIds = listResult.getData().stream().map(MemberSimpleResp::getUserId)
                        .collect(Collectors.toList());
                Map<String, Object> paramMap = new HashMap<>(8);
                paramMap.put("companyId", order.getReceiptCompanyId());
                paramMap.put("payNo", order.getPayNo());
                paramMap.put("mainOrderNo", order.getMainOrderNo());
                paramMap.put("payName", detail.getPayName());
                CompanyResp payCompanyResp = companyService.queryCompany(order.getPayCompanyId());
                paramMap.put("payCompany", receiptOrderService.setCompanyName(payCompanyResp.getCompanyName(), order.getPayCompanyName()));
                paramMap.put("amount", rodReq.getPayAmount().add(ObjectUtils.isNull(rodReq.getBalancePayAmount()) ?
                        BigDecimal.ZERO : rodReq.getBalancePayAmount()).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
                CompanyResp companyResp = companyService.queryCompany(order.getReceiptCompanyId());
                paramMap.put("funcNameCompany", companyResp.getCompanyName());
                messagePushService.pubFinancePush(companyResp.getId(), null, userIds, paramMap, NmsTemplateEnums.FINANCE_MANAGER_RECEIPT_NOTICE);
            }
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("收款单明细更新(非快捷)-异常:{}", e);
            throw new BusinessException(CommonResultCode.CommonResultEnum.SYSTEM_EXCEPTION.getCode(),
                    RECEIPT_ORDER_OPTION_EXCEPTION.getMessage());
        }
    }

    @Override
    public void onlineUpdateReceiptOrderDetail(ReceiptOrderQuickNotifyReq req, ReceiptOnline online, Integer payPay) {
        //根据收款记录编号查询对应的明细
        List<ReceiptOrderDetail> rodList = receiptOrderDetailManager.findReceiptOrderDetailByPayOrderNo(req.getPayOrderNo());
        if (CollectionUtils.isEmpty(rodList)) {
            throw new BusinessException(RECEIPT_ORDER_DETAIL_IS_NOT_EXISTS.getCode(), RECEIPT_ORDER_DETAIL_IS_NOT_EXISTS.getMessage());
        }
        log.info("查询付款单明细：payOrderNo:{},rodList:{}", req.getPayOrderNo(), JSON.toJSONString(rodList));
        List<Long> receiptIds = rodList.stream().map(ReceiptOrderDetail::getReceiptId).collect(Collectors.toList());
        List<ReceiptOrder> orders = receiptOrderManager.list(new LambdaQueryWrapper<ReceiptOrder>()
                .eq(ReceiptOrder::getReceiptStatus, ReceiptStatusEnums.RECEIPT_PAYING.getCode())
                .in(ReceiptOrder::getId, receiptIds)
        );
        String tenantId = orders.stream().map(ReceiptOrder::getTenantId).findFirst().get();
        Map<Long, ReceiptOrder> orderMap = orders.stream().collect(Collectors.toMap(ReceiptOrder::getId, r -> r));
        //款项下所有已完成明细
        List<ReceiptOrderDetail> allDetails = receiptOrderDetailManager.list(new LambdaQueryWrapper<ReceiptOrderDetail>()
                .eq(ReceiptOrderDetail::getIsReject, false)
                .eq(ReceiptOrderDetail::getIsDeleted, false)
                .eq(ReceiptOrderDetail::getIsCancel, false)
                .in(ReceiptOrderDetail::getReceiptId, receiptIds)
                .eq(ReceiptOrderDetail::getPayStatus, ReceiptOrderDetailPayStatusEnums.PAY_SUCCESS.getCode())
        );
        Map<Long, BigDecimal> orderPayAmountMap = allDetails.stream().collect(Collectors.groupingBy(ReceiptOrderDetail::getReceiptId,
                Collectors.mapping(r -> r.getActualAmount().add(r.getBalanceAmount()),
                        Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        List<OnlineSplit> splits = splitManager.list(new LambdaQueryWrapper<OnlineSplit>()
                .in(OnlineSplit::getReceiptId, receiptIds)
                .eq(OnlineSplit::getOnlineId, online.getId())
        );
        List<Integer> payCompanyIds = orders.stream().map(ReceiptOrder::getPayCompanyId).collect(Collectors.toList());
        List<Integer> receiptCompanyIds = orders.stream().map(ReceiptOrder::getReceiptCompanyId).collect(Collectors.toList());
        List<AccountBalance> accountBalances = accountBalanceManager.list(new LambdaQueryWrapper<AccountBalance>()
                .in(AccountBalance::getCompanyId, payCompanyIds)
                .in(AccountBalance::getUpCompanyId, receiptCompanyIds)
                .eq(AccountBalance::getAccountType, AccountTypeEnums.NORMALLY_ACCOUNT.getCode())
        );
        Map<String, AccountBalance> accountBalanceMap = accountBalances.stream().collect(Collectors.toMap(r ->
                r.getCompanyId() + "_" + r.getUpCompanyId(), r -> r));
        Map<Long, ReceiptOrder> receiptOrderMap = orders.stream().collect(Collectors.toMap(ReceiptOrder::getOrderNo, r -> r,
                (r1, r2) -> r2));
        online.setPayTradeNo(req.getPayTradeNo());

        Map<Long, OnlineSplit> splitMap = splits.stream().collect(Collectors.toMap(OnlineSplit::getReceiptId, r -> r));
        BigDecimal devAmount = req.getPayAmount();
        List<PayCallBackReq> payCallBackReqList = new ArrayList<>();
        List<ReceiptOrder> finishOrderList = new ArrayList<>();
        for (ReceiptOrderDetail detail : rodList) {
            ReceiptOrder receiptOrder = orderMap.get(detail.getReceiptId());
            OnlineSplit split = splitMap.get(receiptOrder.getId());
            Boolean isPart = false;
            BigDecimal actualAmount = BigDecimal.ZERO;
            BigDecimal partAmount = BigDecimal.ZERO;
            if (ObjectUtils.isNull(split)) {
                if (devAmount.compareTo(detail.getReceiveAmount()) < 0) {
                    isPart = true;
                    actualAmount = devAmount;
                    partAmount = detail.getReceiveAmount().subtract(devAmount);
                } else {
                    actualAmount = detail.getReceiveAmount();
                    devAmount = devAmount.subtract(detail.getReceiveAmount());
                }
            } else {
                if (split.getAmount().compareTo(detail.getReceiveAmount()) < 0) {
                    isPart = true;
                    partAmount = detail.getReceiveAmount().subtract(split.getAmount());
                } else {
                    devAmount = devAmount.subtract(split.getAmount());
                }
                actualAmount = split.getAmount();
            }
            detail.setPayWay(req.getPayWay());
            detail.setActualAmount(actualAmount);
            detail.setPayTime(LocalDateTime.now());
            detail.setPayUserId(req.getPayUserId());
            detail.setOutTradeNo(req.getOutTradeNo());
            detail.setUpdateTime(LocalDateTime.now());
            detail.setConfirmTime(LocalDateTime.now());
            detail.setPayTradeNo(req.getPayTradeNo());
            detail.setReceiveAmount(actualAmount);
            detail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_SUCCESS.getCode());
            receiptOrderDetailManager.updateById(detail);
            if (isPart) {
                //部分支付
                ReceiptOrderDetail orderDetail = new ReceiptOrderDetail();
                orderDetail.setIsCredit(false);
                orderDetail.setFundsAmount(partAmount);
                orderDetail.setReceiveAmount(partAmount);
                orderDetail.setLinkId(detail.getLinkId());
                orderDetail.setPayName(detail.getPayName());
                orderDetail.setCreateTime(LocalDateTime.now());
                orderDetail.setReceiptId(detail.getReceiptId());
                orderDetail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_WAIT.getCode());
                receiptOrderDetailManager.saveOrUpdate(orderDetail);
            }
            BigDecimal payAmount = ObjectUtils.isEmpty(orderPayAmountMap.get(detail.getReceiptId())) ? BigDecimal.ZERO
                    : orderPayAmountMap.get(detail.getReceiptId());
            ReceiptOrder order = orderMap.get(detail.getReceiptId());
            if (order.getShouldAmount().subtract(payAmount).compareTo(actualAmount) <= 0) {
                //更新主单为快捷支付
                receiptOrder.setPayMode(ReceiptOrderPayModeEnum.QUICK.getCode());
                receiptOrder.setReceiptStatus(ReceiptStatusEnums.RECEIPT_SUCCESS.getCode());
                receiptOrderManager.updateById(receiptOrder);
                finishOrderList.add(receiptOrder);
            }
            String key = receiptOrder.getPayCompanyId() + "_" + receiptOrder.getReceiptCompanyId();
            AccountBalance account = accountBalanceMap.get(key);
            //快捷支付记账-cost
            CostItemStaveParam cisp = CopyObjectUtils.copyAtoB(account, CostItemStaveParam.class);
            cisp.setAmount(actualAmount);
            cisp.setAccountId(account.getId());
            cisp.setBusinessPayNo(receiptOrder.getPayNo());
            cisp.setBusinessId(detail.getId());
            cisp.setBusinessNo(receiptOrder.getMainOrderNo());
            cisp.setBusinessOrderNo(receiptOrder.getOrderNo());
            cisp.setPayWayEnums(detail.getPayWay());
            cisp.setCostStatus(CostItemStatusEnums.FINISHED.getCode());
            cisp.setTypeEnums(CostTypeEnums.COST_ITEM_EXPEND.getCode());
            costItemService.quickPayCostItemStave(cisp);

            //通知订单-支付单确认结果：1-收款成功 2-驳回收款
            PayCallBackReq payCallBackReq = new PayCallBackReq();
            payCallBackReq.setPayConfirmResult(1);
            payCallBackReq.setPayNo(receiptOrder.getPayNo());//付款单编号集合payNos
            payCallBackReq.setPayeeMember(null);//线上通知获取不到MemberID
            payCallBackReq.setRejectReason(null);
            payCallBackReq.setPayeeTime(detail.getConfirmTime());
            payCallBackReq.setPayWay(payPay);
            payCallBackReq.setPartPayAmount(actualAmount);
            payCallBackReq.setBreakAmount(detail.getBreakAmount());
            payCallBackReq.setInterestAmount(detail.getInterestAmount());
            payCallBackReq.setReceiptOrderDetailId(detail.getId().intValue());
            payCallBackReq.setIsPartPay(isPart ? 1 : 0);
            payCallBackReq.setPayUserId(detail.getPayUserId());
            payCallBackReq.setTransactionId(detail.getOutTradeNo());
            payCallBackReqList.add(payCallBackReq);
            log.info("收款单明细更新-快捷orderPayStatusCallBack payNo:{},payOrderNo:{}", receiptOrder.getPayNo(), req.getPayOrderNo());
            //超时违约金大于0，则更新违约已使用额度
            updateBreakUseAmount(detail);
            //释放锁
            log.info("收款单明细更新-快捷-操作成功");
            Result<List<MemberSimpleResp>> result1 = permissionFeign.queryMemberInfoBy(receiptOrder.getReceiptCompanyId(),
                    "E_001_001_001_002");
            log.info("获取收款方公司成员信息membersE_001_001_001_002：{}", JSONObject.toJSONString(result1));
            List<Integer> userIds = new ArrayList<>();
            if (result1.isSuccess() && ObjectUtils.isNotNull(result1.getData())) {
                userIds.addAll(result1.getData().stream().map(MemberSimpleResp::getUserId)
                        .collect(Collectors.toList()));
            }
            if (CollectionUtils.isNotEmpty(userIds)) {
                Map<String, Object> paramMap = new HashMap<>();
                paramMap.put("companyId", receiptOrder.getReceiptCompanyId());
                paramMap.put("payNo", receiptOrder.getPayNo());
                paramMap.put("mainOrderNo", receiptOrder.getMainOrderNo());
                paramMap.put("payName", detail.getPayName());
                paramMap.put("payWay", ReceiptOrderPayWayEnums.getByCode(detail.getPayWay()).getDesc());
                CompanyResp payCompanyResp = companyService.queryCompany(receiptOrder.getPayCompanyId());
                paramMap.put("payCompany", receiptOrderService.setCompanyName(payCompanyResp.getCompanyName(), receiptOrder.getPayCompanyName()));
                CompanyResp companyResp = companyService.queryCompany(receiptOrder.getReceiptCompanyId());
                paramMap.put("funcNameCompany", companyResp.getCompanyName());
                paramMap.put("amount", actualAmount.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
                messagePushService.pubFinancePush(companyResp.getId(), null, userIds, paramMap, NmsTemplateEnums.FINANCE_MANAGER_NOT_RECEIPT_NOTICE);
            }
        }
        online.setChannelCode(req.getPayWay());
        //将收款记录表online_result状态更新为已完成
        receiptOnlineManager.updateReceiptOnlineStatus(req.getPayOrderNo(), req.getPayTradeNo());
        Set<Long> orderNos = orders.stream().map(ReceiptOrder::getOrderNo).collect(Collectors.toSet());
        List<AccountingTrial> trials = trialManager.list(new LambdaQueryWrapper<AccountingTrial>()
                .in(AccountingTrial::getOrderNo, orderNos)
        );
        if (CollectionUtils.isNotEmpty(trials)) {
            //是否有执行自动分账
            loadingAutomaticAccounting(receiptOrderMap, online, splits);
        } else {
            SupportCpcnMchQueryReq mchQueryReq = new SupportCpcnMchQueryReq();
            mchQueryReq.setTenantId(tenantId);
            Result<IPaySupportCpcnMchResp> cpcnMch = supportMchFeignClient.cpcnMch(mchQueryReq);
            Integer platCompanyId = orders.stream().findFirst().get().getReceiptCompanyId();
            if (ObjectUtils.isNotNull(cpcnMch.getData())) {
                platCompanyId = cpcnMch.getData().getCompanyId();
            }
            Integer orderType = orders.stream().findFirst().get().getOrderType();
            LocalDateTime now = LocalDateTime.now();
            //是否执行分账任务
            List<AccountingSplitItem> items = new ArrayList<>();
            //一笔支付流水一个分账任务批次
            AccountingSplit accountingSplit = new AccountingSplit();
            accountingSplit.setOnlineId(online.getId());
            accountingSplit.setPayOrderNo(online.getPayOrderNo());
            accountingSplit.setPayTradeNo(req.getPayTradeNo());
            accountingSplit.setOutTradeNo(req.getOutTradeNo());
            accountingSplit.setAmount(online.getPayAmount());
            accountingSplit.setCompanyId(platCompanyId);
            accountingSplit.setBatchStatus(AccountingBatchStatus.UN_REACH.getStatus());
            accountingSplit.setChannelCode(req.getPayWay());
            accountingSplit.setPayTime(req.getPayTime());
            if (CollectionUtils.isNotEmpty(splits) && req.getPayWay().equals(ReceiptOrderPayWayEnums.CPCN_PAY.getCode()) &&
                    orderType.equals(OrderTypeEnums.MALL_ORDER.getCode())) {
                List<Long> itemIds = splits.stream().map(BaseEntity::getId).collect(Collectors.toList());
                List<OnlineSplitCategory> splitCategories = splitCategoryManager.list(new LambdaQueryWrapper<OnlineSplitCategory>()
                        .eq(OnlineSplitCategory::getOnlineId, online.getId())
                        .in(OnlineSplitCategory::getItemId, itemIds)
                );
                Map<Long, List<OnlineSplitCategory>> categoryListMap = splitCategories.stream().collect(Collectors
                        .groupingBy(OnlineSplitCategory::getItemId));
                Map<String, SupportAccountingRuleResp> ruleRespMap = new HashMap<>();
                if (CollectionUtils.isNotEmpty(splitCategories)) {
                    List<SupportAccountingSkuMatchReq> skuMatchList = new ArrayList<>();
                    Map<Long, List<Integer>> receiptSkuMap = splitCategories.stream().collect(Collectors.groupingBy(
                            OnlineSplitCategory::getReceiptId, Collectors.mapping(OnlineSplitCategory::getSkuId, Collectors.toList())));
                    Map<Integer, List<Integer>> companySkusMap = new HashMap<>();
                    receiptSkuMap.entrySet().stream().forEach(r -> {
                        Long receiptId = r.getKey();
                        ReceiptOrder order = orderMap.get(receiptId);
                        if (companySkusMap.get(order.getReceiptCompanyId()) != null) {
                            companySkusMap.get(order.getReceiptCompanyId()).addAll(r.getValue());
                        } else {
                            companySkusMap.put(order.getReceiptCompanyId(), r.getValue());
                        }
                    });
                    companySkusMap.entrySet().forEach(r -> {
                        SupportAccountingSkuMatchReq skuMatchReq = new SupportAccountingSkuMatchReq();
                        skuMatchReq.setCompanyId(r.getKey());
                        skuMatchReq.setSkuIds(r.getValue());
                        skuMatchList.add(skuMatchReq);
                    });
                    Integer groupOrderId = splits.stream().filter(r -> ObjectUtils.isNotNull(r.getGroupOrderId()))
                            .map(OnlineSplit::getGroupOrderId).findFirst().orElse(null);
                    Boolean isGroupOrder = ObjectUtils.isNull(groupOrderId) || groupOrderId == 0 ? false : true;
                    SupportAccountingRuleMatchReq ruleQueryReq = new SupportAccountingRuleMatchReq();
                    ruleQueryReq.setOrderType(orderType);
                    ruleQueryReq.setIsGroupOrder(isGroupOrder);
                    ruleQueryReq.setSkuMatchList(skuMatchList);
                    ruleQueryReq.setTenantId(tenantId);
                    //查询支付中心设置商品分账规则
                    Result<List<SupportAccountingRuleResp>> ruleResult = iPayAccountingClient.batchMatchAccountingRule(ruleQueryReq);
                    if (ruleResult.getCode() != 0) {
                        log.error("【平台业务操作失败】查询支付中心分账设置异常error：{}", ruleResult.getMessage());
                        throw new BusinessException(51200, "查询支付中心分账设置异常");
                    }
                    List<SupportAccountingRuleResp> ruleResps = ruleResult.getData();
                    ruleRespMap.putAll(ruleResps.stream().collect(Collectors.toMap(r -> r.getCompanyId() + "_" + r.getSkuId(), r -> r)));
                }
                for (OnlineSplit r : splits) {
                    ReceiptOrder order = orderMap.get(r.getReceiptId());
                    List<OnlineSplitCategory> categoryList = categoryListMap.get(r.getId());
                    BigDecimal amountForPlatform = BigDecimal.ZERO;
                    BigDecimal amountForFactory = BigDecimal.ZERO;
                    if (CollectionUtils.isNotEmpty(categoryList)) {
                        for (OnlineSplitCategory s : categoryList) {
                            SupportAccountingRuleResp ruleResp = ruleRespMap.get(order.getReceiptCompanyId() + "_" + s.getSkuId());
                            if (ObjectUtils.isNull(ruleResp)) {
                                this.initSplitItemNoMatched(items, order, r, s, platCompanyId);
                                continue;
                            }
                            List<SupportAccountingRulePartResp> partResps = ruleResp.getPartList();
                            if (CollectionUtils.isEmpty(partResps)) {
                                this.initSplitItemNoMatched(items, order, r, s, platCompanyId);
                                continue;
                            }
                            BigDecimal platAmount = BigDecimal.ZERO;
                            BigDecimal prop = partResps.stream().map(SupportAccountingRulePartResp::getAccountingProp)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                            Boolean isProp = false;
                            if (prop.compareTo(BigDecimal.valueOf(100)) < 0) {
                                isProp = true;
                            }
                            for (SupportAccountingRulePartResp t : partResps) {
                                AccountingSplitItem splitItem = CopyObjectUtils.copyAtoB(t, AccountingSplitItem.class);
                                if (order.getReceiptCompanyId().equals(platCompanyId)) {
                                    splitItem.setMemberType(AccountingMemberTypeEnums.PLATFORM.getCode());
                                }
                                splitItem.setCompanyId(order.getReceiptCompanyId());
                                splitItem.setAccountingRuleId(t.getRuleId());
                                splitItem.setSplitItemId(r.getId());
                                splitItem.setReceiptId(order.getId());
                                splitItem.setPayNo(order.getPayNo());
                                splitItem.setMainOrderNo(order.getMainOrderNo());
                                splitItem.setSplitItemNo(NumberSequence.getSplitNO());
                                splitItem.setSplitStatus(AccountingStatusEnums.WAIT_ACCOUNTING.getCode());
                                splitItem.setAmount(s.getAmount());
                                splitItem.setSplitCategoryId(s.getCategoryId());
                                splitItem.setAccountingPorp(t.getAccountingProp());
                                if (isProp) {
                                    splitItem.setSplitAmount(s.getAmount().multiply(t.getAccountingProp())
                                            .divide(BigDecimal.valueOf(100))
                                            .setScale(2, BigDecimal.ROUND_HALF_UP));
                                    if (splitItem.getMemberType().equals(AccountingMemberTypeEnums.PLATFORM.getCode())) {
                                        splitItem.setCompanyId(platCompanyId);
                                        amountForPlatform = amountForPlatform.add(splitItem.getSplitAmount());
                                    } else {
                                        amountForFactory = amountForFactory.add(splitItem.getSplitAmount());
                                    }
                                } else {
                                    if (splitItem.getMemberType().equals(AccountingMemberTypeEnums.PLATFORM.getCode())) {
                                        platAmount = splitItem.getAmount().multiply(splitItem.getAccountingPorp())
                                                .divide(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                                        splitItem.setSplitAmount(platAmount);
                                        splitItem.setCompanyId(platCompanyId);
                                        amountForPlatform = amountForPlatform.add(splitItem.getSplitAmount());
                                    } else {
                                        splitItem.setSplitAmount(s.getAmount().subtract(platAmount));
                                        amountForFactory = amountForFactory.add(splitItem.getSplitAmount());
                                    }
                                }
                                if (t.getAccountingType().equals(AccountingTypeEnums.AUTOMATIC.getCode())) {
                                    splitItem.setAccountingTime(now.plusHours(8L).plusDays(t.getAccountingDays()).toLocalDate());
                                }
                                splitItem.setActualSplitAmount(splitItem.getSplitAmount());
                                splitItem.setSkuId(s.getSkuId());
                                splitItem.setDiscount(r.getDiscount());
                                splitItem.setGroupOrderId(r.getGroupOrderId());
                                splitItem.setAccountingAround(ruleResp.getAccountingAround());
                                Integer accountingAround = ruleResp.getAccountingAround();
                                AccountingPointEnums status = accountingAround.equals(AccountingAroundEnums.PRE_ACCOUNTING.getCode())
                                        ? AccountingPointEnums.ABLE_ACCOUNTING : AccountingPointEnums.UNABLE_ACCOUNTING;
                                splitItem.setSplitPoint(status.getCode());
                                if (!r.getDiscount()) {
                                    items.add(splitItem);
                                }
                            }
                            if (r.getDiscount()) {
                                AccountingSplitItem splitFactoryItem = new AccountingSplitItem();
                                splitFactoryItem.setSplitItemId(r.getId());
                                splitFactoryItem.setSplitItemNo(NumberSequence.getSplitNO());
                                splitFactoryItem.setSplitStatus(AccountingStatusEnums.WAIT_ACCOUNTING.getCode());
                                splitFactoryItem.setGroupOrderId(r.getGroupOrderId());
                                splitFactoryItem.setDiscount(r.getDiscount());
                                splitFactoryItem.setReceiptId(r.getReceiptId());
                                splitFactoryItem.setAccountingId(accountingSplit.getId());
                                splitFactoryItem.setMemberType(AccountingMemberTypeEnums.FACTORY.getCode());
                                splitFactoryItem.setCompanyId(order.getReceiptCompanyId());
                                splitFactoryItem.setSplitAmount(amountForFactory);
                                splitFactoryItem.setActualSplitAmount(amountForFactory);
                                splitFactoryItem.setSplitPoint(AccountingPointEnums.ABLE_ACCOUNTING.getCode());
                                splitFactoryItem.setAmount(r.getAmount());
                                splitFactoryItem.setPayNo(order.getPayNo());
                                splitFactoryItem.setMainOrderNo(order.getMainOrderNo());
                                splitFactoryItem.setAccountingAround(0);
                                AccountingSplitItem splitPlatItem = new AccountingSplitItem();
                                splitPlatItem.setSplitItemId(r.getId());
                                splitPlatItem.setSplitItemNo(NumberSequence.getSplitNO());
                                splitPlatItem.setSplitStatus(AccountingStatusEnums.WAIT_ACCOUNTING.getCode());
                                splitPlatItem.setGroupOrderId(r.getGroupOrderId());
                                splitPlatItem.setDiscount(r.getDiscount());
                                splitPlatItem.setReceiptId(r.getReceiptId());
                                splitPlatItem.setAccountingId(accountingSplit.getId());
                                splitPlatItem.setMemberType(AccountingMemberTypeEnums.PLATFORM.getCode());
                                splitPlatItem.setCompanyId(platCompanyId);
                                splitPlatItem.setSplitAmount(amountForPlatform);
                                splitPlatItem.setActualSplitAmount(amountForPlatform);
                                splitPlatItem.setSplitPoint(AccountingPointEnums.ABLE_ACCOUNTING.getCode());
                                splitPlatItem.setAmount(r.getAmount());
                                splitPlatItem.setPayNo(order.getPayNo());
                                splitPlatItem.setMainOrderNo(order.getMainOrderNo());
                                splitPlatItem.setAccountingAround(0);
                                items.add(splitFactoryItem);
                                items.add(splitPlatItem);
                            }
                        }
                    }
                }
            }
            List<AccountingSplitItem> ableList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(items)) {
                accountingSplitManager.saveOrUpdate(accountingSplit);
                items.stream().forEach(r -> r.setAccountingId(accountingSplit.getId()));
                accountingSplitItemManager.saveOrUpdateBatch(items);
            }
            if (CollectionUtils.isNotEmpty(finishOrderList)) {
                List<Long> orderList = finishOrderList.stream().map(ReceiptOrder::getId).collect(Collectors.toList());
                ableList.addAll(items.stream().filter(r -> orderList.contains(r.getReceiptId())).collect(Collectors.toList()));
            }
            if (CollectionUtils.isNotEmpty(ableList)) {
                List<Long> receiptIdList = ableList.stream().map(AccountingSplitItem::getReceiptId).distinct().collect(Collectors.toList());
                List<AccountingSplitItem> allList = accountingSplitItemManager.list(new LambdaQueryWrapper<AccountingSplitItem>()
                        .in(AccountingSplitItem::getReceiptId, receiptIdList)
                        .eq(AccountingSplitItem::getSplitStatus, AccountingStatusEnums.UN_REACH.getCode())
                );
                if (CollectionUtils.isNotEmpty(allList)) {
                    List<Long> accountingIds = allList.stream().map(AccountingSplitItem::getAccountingId).collect(Collectors.toList());
                    List<AccountingSplit> splitsList = accountingSplitManager.list(new LambdaQueryWrapper<AccountingSplit>()
                            .in(BaseEntity::getId, accountingIds)
                            .eq(AccountingSplit::getBatchStatus, AccountingBatchStatus.UN_REACH.getStatus())
                    );
                    if (CollectionUtils.isNotEmpty(splitsList)) {
                        splitsList.stream().forEach(r -> r.setBatchStatus(AccountingBatchStatus.ACCOUNTING.getStatus()));
                        accountingSplitManager.saveOrUpdateBatch(splitsList);
                    }
                    allList.stream().forEach(r -> r.setSplitStatus(AccountingStatusEnums.WAIT_ACCOUNTING.getCode()));
                    accountingSplitItemManager.saveOrUpdateBatch(allList);
                }
                if (ObjectUtils.isNotEmpty(accountingSplit)) {
                    accountingSplit.setBatchStatus(AccountingBatchStatus.ACCOUNTING.getStatus());
                    accountingSplitManager.saveOrUpdate(accountingSplit);
                }
                ableList.stream().forEach(r -> r.setSplitStatus(AccountingStatusEnums.WAIT_ACCOUNTING.getCode()));
                accountingSplitItemManager.saveOrUpdateBatch(ableList);
            }
        }

        orderFeignService.batchOnlineOrderPayStatusCallBack(payCallBackReqList);
    }


    /**
     * 自动分账创建批次计划
     *
     * @param orderMap
     * @param online
     * @param splits
     */
    public void loadingAutomaticAccounting(Map<Long, ReceiptOrder> orderMap, ReceiptOnline online, List<OnlineSplit> splits) {
        if (!redisLock.getLock(online.getPayTradeNo(), lockOutTime, TimeUnit.SECONDS)) {
            log.info("重复提交创建分账计划：online：{}", JSONObject.toJSONString(online));
        }
        List<Long> orderNoList = splits.stream().map(OnlineSplit::getOrderNo).collect(Collectors.toList());
        AccountingTrialItemDTO dto = new AccountingTrialItemDTO();
        dto.setOrderNoList(orderNoList);
        List<AccountingTrialAutomaticDTO> itemDTOS = trialItemManager.listAutomaticItemByDto(dto);
        log.info("本次自动分账数据筛选itemDTOS:{}", JSONObject.toJSONString(itemDTOS));
        if (CollectionUtils.isEmpty(itemDTOS)) {
            return;
        }
        Map<String, AccountingTrialAutomaticDTO> automaticDTOMap = itemDTOS.stream().collect(Collectors
                .toMap(r -> r.getTrialId() + "_" + r.getCompanyId(), r -> r));
        dto = new AccountingTrialItemDTO();
        List<Long> trialIds = itemDTOS.stream().map(AccountingTrialAutomaticDTO::getTrialId).collect(Collectors.toList());
        dto.setTrialIds(trialIds);
        List<AccountingTrialItemDTO> trialItems = trialItemManager.automaticItemListByDto(dto);
        log.info("本次自动分账数据筛选items:{}", JSONObject.toJSONString(trialItems));
        if (CollectionUtils.isEmpty(trialItems)) {
            return;
        }
        //所有试算订单
        List<AccountingTrial> trials = trialManager.listByIds(trialIds);
        trials.stream().forEach(r -> r.setIsPay(true));
        trialManager.saveOrUpdateBatch(trials);
        //试算订单分账方信息
        List<AccountingTrialPart> trialParts = trialPartManager.list(new LambdaQueryWrapper<AccountingTrialPart>()
                .eq(BaseEntity::getIsDeleted, false)
                .in(AccountingTrialPart::getTrialId, trialIds)
        );
        Map<Long, List<AccountingTrialPart>> trialPartMap = trialParts.stream().collect(Collectors.groupingBy(AccountingTrialPart::getTrialId));
        Map<Long, AccountingTrial> trialMap = trials.stream().collect(Collectors.toMap(BaseEntity::getId, r -> r));
        LocalDate now = LocalDateTime.now().plusHours(8L).toLocalDate();
        Map<Long, List<OnlineSplit>> splitMap = splits.stream().collect(Collectors.groupingBy(OnlineSplit::getOrderNo));
        BigDecimal payAmount = online.getPayAmount();
        BigDecimal hasSplitAmount = BigDecimal.ZERO;
        List<AccountingBatch> batches = new ArrayList<>();
        Map<Integer, Map<Long, List<AccountingTrialItemDTO>>> longMapMap = trialItems.stream().sorted(Comparator
                .comparing(AccountingTrialItem::getMemberType)).collect(Collectors.groupingBy(AccountingTrialItem::getMemberType,
                Collectors.groupingBy(AccountingTrialItem::getTrialId)));
        log.info("本次参与计算扣减金额的longMapMap：{}", JSONObject.toJSONString(longMapMap));
        List<String> hasKey = new ArrayList<>();
        for (Map.Entry<Integer, Map<Long, List<AccountingTrialItemDTO>>> mapEntry : longMapMap.entrySet()) {
            for (Map.Entry<Long, List<AccountingTrialItemDTO>> valueEntry : mapEntry.getValue().entrySet()) {
                AccountingTrial trial = trialMap.get(valueEntry.getKey());
                List<AccountingTrialPart> parts = trialPartMap.get(trial.getId());
                List<OnlineSplit> onlineSplits = splitMap.get(trial.getOrderNo());
                OnlineSplit split = onlineSplits.stream().findFirst().get();
                ReceiptOrder order = orderMap.get(trial.getOrderNo());
                List<AccountingTrialItemDTO> dtos = valueEntry.getValue();
                AccountingTrialItemDTO trialItemDTO = dtos.stream().findFirst().get();
                AccountingTrialPart trialPart = parts.stream().filter(s -> s.getCompanyId().equals(trialItemDTO.getCompanyId()))
                        .findFirst().get();
                BigDecimal divide = trial.getAmount().subtract(trial.getDiscountAmount());
                BigDecimal currentSplitAmount = divide.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
                        split.getAmount().multiply(trialPart.getTrialAmount().subtract(trialPart.getDiscountAmount()))
                                .divide(divide, 2, BigDecimal.ROUND_HALF_UP);
                String key = trialItemDTO.getTrialId() + "_" + trialItemDTO.getCompanyId();
                if (hasKey.contains(key)) {
                    continue;
                }
                hasKey.add(key);
                AccountingTrialAutomaticDTO trialAutomaticDTO = automaticDTOMap.get(key);
                BigDecimal shouldSplitAmount = ObjectUtils.isNull(trialAutomaticDTO) ? BigDecimal.ZERO :
                        trialAutomaticDTO.getSumTrialAmount().subtract(trialAutomaticDTO.getDiscountAmount())
                                .subtract(trialAutomaticDTO.getSumSplitAmount());
                if (shouldSplitAmount.compareTo(BigDecimal.ZERO) <= 0) {
                    continue;
                }
                BigDecimal leaveAmount = payAmount.subtract(hasSplitAmount);
                if (leaveAmount.compareTo(BigDecimal.ZERO) <= 0) {
                    break;
                }
                BigDecimal splitAmount = currentSplitAmount;
                BigDecimal subtract = splitAmount.subtract(shouldSplitAmount);
                if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                    splitAmount = shouldSplitAmount;
                } else {
                    splitAmount = currentSplitAmount;
                }
                hasSplitAmount = hasSplitAmount.add(splitAmount);
                AppThreadLocal.setTenantId(order.getTenantId());
                AppThreadLocal.setSourceCode("hsj");
                AccountingBatch batch = new AccountingBatch();
                batch.setBatchNo(NumberSequence.getAccountingBatchNO());
                batch.setBatchTime(LocalDateTime.now());
                batch.setSplitCompanyId(trialItemDTO.getCompanyId());
                batch.setCompanyId(trialItemDTO.getPlatCompanyId());
                batch.setChannelCode(online.getChannelCode());
                batch.setSplitAmount(splitAmount);
                batch.setMainOrderNo(order.getMainOrderNo());
                batch.setTrialId(trialItemDTO.getTrialId());
                batch.setOrderNo(order.getOrderNo());
                batch.setTenantId(order.getTenantId());
                accountingBatchManager.saveOrUpdate(batch);
                batches.add(batch);
                AccountingStatusEnums statusEnums = AccountingStatusEnums.WAIT_ACCOUNTING;
                Integer splitPoint = trialItemDTO.getSplitPoint();
                if (splitPoint.equals(AccountingPointEnums.UNABLE_ACCOUNTING.getCode())) {
                    statusEnums = AccountingStatusEnums.UN_REACH;
                }
                AccountingBatchItem item = new AccountingBatchItem();
                item.setBatchId(batch.getId());
                item.setTrialId(trialItemDTO.getTrialId());
                item.setItemNo(NumberSequence.getSplitNO());
                item.setAccountingDays(0);
                item.setOnlineId(online.getId());
                item.setOnlineSplitId(split.getId());
                item.setPayTradeNo(online.getPayTradeNo());
                item.setAccountingType(AccountingTypeEnums.AUTOMATIC.getCode());
                item.setSplitStatus(statusEnums.getCode());
                item.setAccountingTime(now);
                item.setCompanyId(trialItemDTO.getCompanyId());
                item.setIsInvalid(false);
                item.setSplitAmount(splitAmount);
                item.setAmount(splitAmount);
                item.setActualSplitAmount(splitAmount);
                item.setTenantId(order.getTenantId());
                batchItemManager.saveOrUpdate(item);
            }
        }
        List<AccountingBatchItem> applyItemList = batchItemManager.list(new LambdaQueryWrapper<AccountingBatchItem>()
                .in(AccountingBatchItem::getTrialId, trialIds)
                .eq(AccountingBatchItem::getAccountingType, AccountingTypeEnums.AUTOMATIC.getCode())
                .eq(AccountingBatchItem::getSplitStatus, AccountingStatusEnums.WAIT_ACCOUNTING.getCode())
        );
        if (CollectionUtils.isEmpty(applyItemList)) {
            return;
        }
        applyItemList.stream().forEach(r -> r.setSplitTime(LocalDateTime.now()));
        batchItemManager.saveOrUpdateBatch(applyItemList);
        Set<Long> batchIds = applyItemList.stream().map(AccountingBatchItem::getBatchId).collect(Collectors.toSet());
        List<AccountingBatch> batchList = batches.stream().filter(r -> batchIds.contains(r.getId())).collect(Collectors.toList());
        List<AccountingBatchDTO> batchDTOS = CopyObjectUtils.copyAlistToBlist(batchList, AccountingBatchDTO.class);
        List<AccountingBatchItemDTO> batchItemDTOS = CopyObjectUtils.copyAlistToBlist(applyItemList, AccountingBatchItemDTO.class);
        Map<Long, List<AccountingBatchItemDTO>> itemMapList = batchItemDTOS.stream().collect(Collectors
                .groupingBy(AccountingBatchItem::getBatchId));
        batchDTOS.stream().forEach(r -> {
            List<AccountingBatchItemDTO> dtos = itemMapList.get(r.getId());
            r.setItemList(dtos);
        });
        //释放锁
        try {
            redisLock.unlock(online.getPayTradeNo(), String.valueOf(lockOutTime));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //异步发起请求
        paymentAccountingService.batchAccountingApply(batchDTOS);
    }

    /**
     * 未击中规则-初始化分账明细
     *
     * @param items         分账明细
     * @param order         款项主表
     * @param r             线上分账
     * @param s             分账分类
     * @param platCompanyId 平台公司ID
     * @author lidonghao
     * @date 2024/6/29
     */
    public void initSplitItemNoMatched(List<AccountingSplitItem> items, ReceiptOrder order, OnlineSplit r, OnlineSplitCategory s, Integer platCompanyId) {
        if (r.getDiscount()) {
            return;
        }
        AccountingSplitItem splitItem = new AccountingSplitItem();
        splitItem.setIsRuleMatched(false);
        splitItem.setMemberType(AccountingMemberTypeEnums.PLATFORM.getCode());
        splitItem.setCompanyId(platCompanyId);
        splitItem.setAccountingRuleId(null);
        splitItem.setSplitItemId(r.getId());
        splitItem.setReceiptId(order.getId());
        splitItem.setPayNo(order.getPayNo());
        splitItem.setMainOrderNo(order.getMainOrderNo());
        splitItem.setSplitItemNo(NumberSequence.getSplitNO());
        splitItem.setSplitStatus(AccountingStatusEnums.WAIT_ACCOUNTING.getCode());
        splitItem.setAmount(s.getAmount());
        splitItem.setSplitCategoryId(s.getCategoryId());
        splitItem.setAccountingPorp(BigDecimal.valueOf(100));
        splitItem.setSplitAmount(s.getAmount());
        splitItem.setAccountingTime(LocalDateTime.now().plusHours(8L).plusDays(1).toLocalDate());
        splitItem.setActualSplitAmount(splitItem.getSplitAmount());
        splitItem.setSkuId(s.getSkuId());
        splitItem.setDiscount(r.getDiscount());
        splitItem.setGroupOrderId(r.getGroupOrderId());
        splitItem.setAccountingAround(0);
        splitItem.setSplitPoint(AccountingPointEnums.ABLE_ACCOUNTING.getCode());
        splitItem.setAccountingType(AccountingTypeEnums.AUTOMATIC.getCode());
        log.info("initSplitItemNoMatched:{}", JSON.toJSONString(splitItem));
        items.add(splitItem);
    }

    /**
     * 赊销支付业务处理
     *
     * @param rodReq
     */
    public void creditReceiptHandler(ReceiptOrderDetailReq rodReq, ReceiptOrderDetail receiptOrderDetail) {
        BigDecimal receiveAmount = BigDecimalUtils.amountScale(receiptOrderDetail.getReceiveAmount());
        //获取收款单信息
        ReceiptOrder receiptOrder = receiptOrderManager.queryReceiptOrder(receiptOrderDetail.getReceiptId());

        //不能同时支持转账加余额（只能二选一）
        if (ObjectUtils.isNotEmpty(rodReq.getBalancePayAmount()) && rodReq.getBalancePayAmount().compareTo(BigDecimal.ZERO) > 0
                && ObjectUtils.isNotEmpty(rodReq.getPayAmount()) && rodReq.getPayAmount().compareTo(BigDecimal.ZERO) > 0) {
            log.info("Transfer and balance cannot be supported at the same time,payAmount:{},balancePayAmount:{}", rodReq.getPayAmount(), rodReq.getBalancePayAmount());
            throw new BusinessException(RECEIPT_CANNOT_SUPPORT_TRANSFER_AND_BALANCE.getCode(),
                    RECEIPT_CANNOT_SUPPORT_TRANSFER_AND_BALANCE.getMessage());
        }
        //全额赊销
        if ((ObjectUtils.isEmpty(rodReq.getPayAmount()) || rodReq.getPayAmount().compareTo(BigDecimal.ZERO) == 0) &&
                (ObjectUtils.isEmpty(rodReq.getBalancePayAmount()) || rodReq.getBalancePayAmount().compareTo(BigDecimal.ZERO) == 0)) {
            //校验金额跟应收金额是否一致
            log.info("creditReceiptHandler isAllCredit creditAmount:{}, receiveAmount:{},payNo:{}", rodReq.getCreditAmount(), receiveAmount, receiptOrder.getPayNo());
            if (!BigDecimalUtils.checkAmount(rodReq.getCreditAmount(), receiveAmount)) {
                throw new BusinessException(RECEIPT_ORDER_PAY_AMOUNT_MISMATCH.getCode(),
                        RECEIPT_ORDER_PAY_AMOUNT_MISMATCH.getMessage());
            }
            //赊销处理-全额赊销
            creditDispose(rodReq, receiptOrder, receiptOrderDetail, true);
            return;
        }
        //赊销+转账
        if (ObjectUtils.isNotEmpty(rodReq.getPayAmount()) && rodReq.getPayAmount().compareTo(BigDecimal.ZERO) > 0) {
            //校验金额跟应收金额是否一致
            BigDecimal totalAmount = rodReq.getCreditAmount().add(rodReq.getPayAmount());
            log.info("creditReceiptHandler transferPay totalAmount:{},receiveAmount:{},payNo:{}", totalAmount, receiveAmount, receiptOrder.getPayNo());
            if (!BigDecimalUtils.checkAmount(totalAmount, receiveAmount)) {
                throw new BusinessException(RECEIPT_ORDER_PAY_AMOUNT_MISMATCH.getCode(),
                        RECEIPT_ORDER_PAY_AMOUNT_MISMATCH.getMessage());
            }
            //更新主付款单-应收金额和订单金额
            receiptOrder.setOrderAmount(rodReq.getPayAmount());
            receiptOrder.setShouldAmount(rodReq.getPayAmount());
            receiptOrder.setPayMode(ReceiptOrderPayModeEnum.OFFLINE_TRANSFER.getCode());
            receiptOrderManager.updateById(receiptOrder);
            //将原有明细单-更新为待确认的线下转账单
            receiptOrderDetail.setIsCredit(false);
            receiptOrderDetail.setCreditDays(null);
            receiptOrderDetail.setCreditAmount(null);
            receiptOrderDetail.setCreditStatus(null);
            receiptOrderDetail.setPayTime(LocalDateTime.now());
            receiptOrderDetail.setUpdateTime(LocalDateTime.now());
            receiptOrderDetail.setVoucherNo(rodReq.getVoucherNo());
            receiptOrderDetail.setTransAmount(rodReq.getPayAmount());
            receiptOrderDetail.setPayTradeNo(rodReq.getPayTradeNo());
            receiptOrderDetail.setFundsAmount(rodReq.getPayAmount());
            receiptOrderDetail.setReceiveAmount(rodReq.getPayAmount());
            receiptOrderDetail.setVoucherUrl(JSON.toJSONString(rodReq.getVoucherUrl()));
            receiptOrderDetail.setPayWay(ReceiptOrderPayWayEnums.OFFLINE_TRANSFER.getCode());
            receiptOrderDetail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_CONFIRM.getCode());
            receiptOrderDetail.setPayUserId(rodReq.getPayUserId());
            receiptOrderDetail.setIsReject(false);
            receiptOrderDetail.setRejectReason(null);
            receiptOrderDetailManager.updateById(receiptOrderDetail);
            //线下支付记账-申请cost
            AccountBalance account = balanceService.getAccount(rodReq.getPlatformAccountId());
            if (account == null) {
                throw new BusinessException(ACCOUNT_DATA_IS_NOT_EXISTS.getCode(),
                        ACCOUNT_DATA_IS_NOT_EXISTS.getMessage());
            }
            CostItemStaveParam cisp = CopyObjectUtils.copyAtoB(account, CostItemStaveParam.class);
            cisp.setAccountId(account.getId());
            cisp.setAmount(rodReq.getPayAmount());
            cisp.setBusinessId(receiptOrderDetail.getId());
            cisp.setBusinessPayNo(receiptOrder.getPayNo());
            cisp.setBusinessNo(receiptOrder.getMainOrderNo());
            cisp.setBusinessOrderNo(receiptOrder.getOrderNo());
            cisp.setCostStatus(CostItemStatusEnums.START.getCode());
            cisp.setTypeEnums(CostTypeEnums.COST_ITEM_EXPEND.getCode());
            cisp.setPayWayEnums(CostWayEnums.COST_ITEM_OFFLINE_TRANSFER.getCode());
            costItemService.startCostItemStave(cisp);
            //赊销处理-非全额赊销
            creditDispose(rodReq, receiptOrder, receiptOrderDetail, false);
            return;
        }
        //赊销+余额
        if (ObjectUtils.isNotEmpty(rodReq.getBalancePayAmount()) && rodReq.getBalancePayAmount().compareTo(BigDecimal.ZERO) > 0) {
            //校验金额跟应收金额是否一致
            BigDecimal totalAmount = rodReq.getCreditAmount().add(rodReq.getBalancePayAmount());
            log.info("creditReceiptHandler balancePay totalAmount:{},receiveAmount:{},payNo:{}",
                    totalAmount, receiveAmount, receiptOrder.getPayNo());
            if (!BigDecimalUtils.checkAmount(totalAmount, receiveAmount)) {
                throw new BusinessException(RECEIPT_ORDER_PAY_AMOUNT_MISMATCH.getCode(),
                        RECEIPT_ORDER_PAY_AMOUNT_MISMATCH.getMessage());
            }
            //更新主单为余额支付
            receiptOrder.setOrderAmount(rodReq.getBalancePayAmount());
            receiptOrder.setShouldAmount(rodReq.getBalancePayAmount());
            receiptOrder.setPayMode(ReceiptOrderPayModeEnum.WALLET.getCode());
            receiptOrderManager.saveOrUpdate(receiptOrder);
            //将原有明细单-更新为待确认的余额支付单
            receiptOrderDetail.setActualAmount(rodReq.getBalancePayAmount());
            receiptOrderDetail.setBalanceAmount(rodReq.getBalancePayAmount());
            receiptOrderDetail.setIsCredit(false);
            receiptOrderDetail.setCreditAmount(null);
            receiptOrderDetail.setCreditStatus(null);
            receiptOrderDetail.setCreditDays(null);
            receiptOrderDetail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_CONFIRM.getCode());
            receiptOrderDetail.setPayWay(ReceiptOrderPayWayEnums.WALLET.getCode());
            receiptOrderDetail.setVoucherNo(rodReq.getVoucherNo());
            receiptOrderDetail.setVoucherUrl(JSON.toJSONString(rodReq.getVoucherUrl()));
            receiptOrderDetail.setPayTradeNo(rodReq.getPayTradeNo());
            receiptOrderDetail.setFundsAmount(rodReq.getBalancePayAmount());
            receiptOrderDetail.setReceiveAmount(rodReq.getBalancePayAmount());
            receiptOrderDetail.setPayTime(LocalDateTime.now());
            receiptOrderDetail.setUpdateTime(LocalDateTime.now());
            receiptOrderDetail.setPayUserId(rodReq.getPayUserId());
            receiptOrderDetail.setIsReject(false);
            receiptOrderDetail.setRejectReason(null);
            receiptOrderDetailManager.updateById(receiptOrderDetail);
            //申请余额变更
            startBalanceItem(rodReq, receiptOrderDetail, receiptOrder);
            //赊销处理-非全额赊销
            creditDispose(rodReq, receiptOrder, receiptOrderDetail, false);
            return;
        }
    }

    /**
     * 超时违约金大于0，则更新违约已使用额度
     *
     * @param detail
     */
    public void updateBreakUseAmount(ReceiptOrderDetail detail) {
        if (ObjectUtils.isNotEmpty(detail.getBreakAmount())
                && detail.getBreakAmount().compareTo(BigDecimal.ZERO) > 0
                && detail.getIsCredit()) {
            ReceiptOrder receiptOrder = receiptOrderManager.queryReceiptOrder(detail.getReceiptId());
            log.info("updateBreakUseAmount payCompanyId= {},receiptCompanyId={},breakAmount={}",
                    receiptOrder.getPayCompanyId(), receiptOrder.getReceiptCompanyId(), detail.getBreakAmount());
            settingManager.updateBreakUseAmount(receiptOrder.getPayCompanyId(), receiptOrder.getReceiptCompanyId(), detail.getBreakAmount());
        }
    }

    /**
     * 组合支付业务处理
     *
     * @param rodReq
     * @param receiptOrderDetail
     */
    public void groupReceiptHandler(ReceiptOrderDetailReq rodReq, ReceiptOrderDetail receiptOrderDetail) {
        BigDecimal payAmount = rodReq.getPayAmount();
        BigDecimal balancePayAmount = rodReq.getBalancePayAmount();
        BigDecimal receiveAmount = BigDecimalUtils.amountScale(receiptOrderDetail.getReceiveAmount());
        //获取收款单信息
        ReceiptOrder receiptOrder = receiptOrderManager.queryReceiptOrder(receiptOrderDetail.getReceiptId());
        log.info("groupReceiptHandler PayAmount:{},balancePayAmount:{},receiveAmount{},payNo:{}",
                payAmount, balancePayAmount, receiveAmount, receiptOrder.getPayNo());

        //校验金额跟应收金额是否一致
        BigDecimal totalAmount = payAmount.add(balancePayAmount);
//        if (!BigDecimalUtils.checkAmount(totalAmount, receiveAmount)) {
//            throw new BusinessException(RECEIPT_ORDER_PAY_AMOUNT_MISMATCH.getCode(),
//                    RECEIPT_ORDER_PAY_AMOUNT_MISMATCH.getMessage());
//        }
        //更新主单为组合支付
//        receiptOrder.setPayMode(ReceiptOrderPayModeEnum.GROUP.getCode());
//        receiptOrderManager.updateById(receiptOrder);
        //组合支付用 转账支付金额和余额支付金额
        receiptOrderDetail.setTransAmount(payAmount);
        receiptOrderDetail.setFundsAmount(totalAmount);
        receiptOrderDetail.setReceiveAmount(totalAmount);
        receiptOrderDetail.setPayTime(LocalDateTime.now());
        receiptOrderDetail.setBalanceAmount(balancePayAmount);
        receiptOrderDetail.setUpdateTime(LocalDateTime.now());
        receiptOrderDetail.setVoucherNo(rodReq.getVoucherNo());
        //将原有明细单-更新为待确认的余额支付单
        receiptOrderDetail.setPayTradeNo(rodReq.getPayTradeNo());
        receiptOrderDetail.setPayName(receiptOrderDetail.getPayName());
        receiptOrderDetail.setPayWay(ReceiptOrderPayWayEnums.GROUP.getCode());
        receiptOrderDetail.setVoucherUrl(JSON.toJSONString(rodReq.getVoucherUrl()));
        receiptOrderDetail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_CONFIRM.getCode());
        receiptOrderDetail.setPayUserId(rodReq.getPayUserId());
        receiptOrderDetail.setIsReject(false);
        receiptOrderDetail.setRejectReason(null);
        receiptOrderDetailManager.updateById(receiptOrderDetail);

        //申请余额变更
        startBalanceItem(rodReq, receiptOrderDetail, receiptOrder);

        //订单数据同步
        orderPaySubmit(rodReq, receiptOrder, receiptOrderDetail, null);
    }


    /**
     * 赊销处理
     *
     * @param req
     * @param order
     * @param detail
     * @param isAllCredit
     */
    public void creditDispose(ReceiptOrderDetailReq req, ReceiptOrder order, ReceiptOrderDetail detail, boolean isAllCredit) {
        //获取赊销配置
        CreditSetting creditSetting = settingManager.queryCreditSetting(order.getPayCompanyId(), order.getReceiptCompanyId());
        log.info("获取赊销配置：{}", creditSetting);
        //校验赊销额度
        creditRecordManager.checkCreditLimit(creditSetting, req.getCreditAmount());
        //获取本次赊销状态
        Integer creditStatus = settingManager.getCreditStatus(creditSetting);
        log.info("获取本次赊销状态：{}", creditStatus);

        //全额赊销
        if (isAllCredit) {
            detail.setPayName(detail.getPayName() + "-全额赊销");
            detail.setIsCredit(true);
            detail.setCreditStatus(creditStatus);
            detail.setCreditAmount(req.getCreditAmount());
            detail.setCreditDays(req.getCreditDays());
            detail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_WAIT.getCode());
            detail.setVoucherNo(null);
            detail.setIsReject(false);
            detail.setRejectReason(null);
            receiptOrderDetailManager.updateById(detail);
            //生成赊销记录
            creditRecordManager.genCreditRecord(req, order, creditSetting, creditStatus);
            //订单数据同步
            orderPaySubmit(req, order, detail, creditStatus);
        } else {
            //订单数据同步--返回赊销付款单的付款编号
            String creditPayNo = orderPaySubmit(req, order, detail, creditStatus);
            log.info("creditReceiptHandler orderPaySubmit 返回赊销付款单编号：{}", creditPayNo);
            if (StringUtils.isEmpty(creditPayNo)) {
                throw new BusinessException(CommonResultCode.CommonResultEnum.SYSTEM_EXCEPTION.getCode(), "订单同步返回赊销单付款编号为空");
            }
            //生成新的赊销收款单
            ReceiptOrder creditReceiptOrder = receiptOrderManager.genCreditReceiptOrder(req, order, detail, creditStatus, creditPayNo);
            //生成赊销记录
            creditRecordManager.genCreditRecord(req, creditReceiptOrder, creditSetting, creditStatus);
        }
    }

    /**
     * 线下转账业务处理
     *
     * @param rodReq
     * @param receiptOrderDetail
     */
    public void offlineTransReceiptHandler(ReceiptOrderDetailReq rodReq, ReceiptOrderDetail receiptOrderDetail) {
        BigDecimal receiveAmount = BigDecimalUtils.amountScale(receiptOrderDetail.getReceiveAmount());
        //获取收款单信息
        ReceiptOrder receiptOrder = receiptOrderManager.queryReceiptOrder(receiptOrderDetail.getReceiptId());
        log.info("offlineTransReceiptHandler payAmount:{},receiveAmount:{},payNo:{}", rodReq.getPayAmount(), receiveAmount, receiptOrder.getPayNo());
        receiptOrderDetail.setPayTime(LocalDateTime.now());
        receiptOrderDetail.setUpdateTime(LocalDateTime.now());
        receiptOrderDetail.setVoucherNo(rodReq.getVoucherNo());
        receiptOrderDetail.setTransAmount(rodReq.getPayAmount());
        receiptOrderDetail.setPayTradeNo(rodReq.getPayTradeNo());
        receiptOrderDetail.setReceiveAmount(rodReq.getPayAmount());
        receiptOrderDetail.setVoucherUrl(JSON.toJSONString(rodReq.getVoucherUrl()));
        receiptOrderDetail.setPayWay(ReceiptOrderPayWayEnums.OFFLINE_TRANSFER.getCode());
        receiptOrderDetail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_CONFIRM.getCode());
        receiptOrderDetail.setPayUserId(rodReq.getPayUserId());
        receiptOrderDetail.setIsReject(false);
        receiptOrderDetail.setRejectReason(null);
        receiptOrderDetail.setBalanceAmount(BigDecimal.ZERO);
        receiptOrderDetailManager.saveOrUpdate(receiptOrderDetail);
        //线下支付记账-申请cost
        AccountBalance account = balanceService.getAccount(rodReq.getPlatformAccountId());
        if (account == null) {
            throw new BusinessException(ACCOUNT_DATA_IS_NOT_EXISTS.getCode(),
                    ACCOUNT_DATA_IS_NOT_EXISTS.getMessage());
        }
        CostItemStaveParam cisp = CopyObjectUtils.copyAtoB(account, CostItemStaveParam.class);
        cisp.setAccountId(account.getId());
        cisp.setAmount(rodReq.getPayAmount());
        cisp.setBusinessPayNo(receiptOrder.getPayNo());
        cisp.setBusinessId(receiptOrderDetail.getId());
        cisp.setBusinessNo(receiptOrder.getMainOrderNo());
        cisp.setBusinessOrderNo(receiptOrder.getOrderNo());
        cisp.setCostStatus(CostItemStatusEnums.START.getCode());
        cisp.setTypeEnums(CostTypeEnums.COST_ITEM_EXPEND.getCode());
        cisp.setPayWayEnums(CostWayEnums.COST_ITEM_OFFLINE_TRANSFER.getCode());
        costItemService.startCostItemStave(cisp);
        //订单数据同步
        orderPaySubmit(rodReq, receiptOrder, receiptOrderDetail, null);

    }

    /**
     * 余额支付业务处理
     *
     * @param req
     * @param detail
     */
    public void walletReceiptHandler(ReceiptOrderDetailReq req, ReceiptOrderDetail detail) {
        BigDecimal balancePayAmount = req.getBalancePayAmount();
        BigDecimal receiveAmount = BigDecimalUtils.amountScale(detail.getReceiveAmount());
        //获取收款单信息
        ReceiptOrder receiptOrder = receiptOrderManager.queryReceiptOrder(detail.getReceiptId());
        log.info("groupReceiptHandler balancePayAmount:{},receiveAmount:{},payNo:{}",
                balancePayAmount, receiveAmount, receiptOrder.getPayNo());

        //转账金额为0，则都是余额支付的
        if (null == balancePayAmount || balancePayAmount.compareTo(BigDecimal.ZERO) == 0) {
            throw new BusinessException(RECEIPT_ORDER_BALANCE_PAY_AMOUNT_IS_NULL.getCode(),
                    RECEIPT_ORDER_BALANCE_PAY_AMOUNT_IS_NULL.getMessage());
        }
        //将原有明细单-更新为待确认的余额支付单
        detail.setPayTime(LocalDateTime.now());
        detail.setFundsAmount(balancePayAmount);
        detail.setUpdateTime(LocalDateTime.now());
        detail.setBalanceAmount(balancePayAmount);
        detail.setPayTradeNo(req.getPayTradeNo());
        detail.setReceiveAmount(balancePayAmount);
        detail.setPayWay(ReceiptOrderPayWayEnums.WALLET.getCode());
        detail.setPayStatus(ReceiptOrderDetailPayStatusEnums.PAY_CONFIRM.getCode());
        detail.setPayUserId(req.getPayUserId());
        detail.setIsReject(false);
        detail.setRejectReason(null);
        detail.setTransAmount(BigDecimal.ZERO);
        receiptOrderDetailManager.updateById(detail);

        //申请余额变更
        startBalanceItem(req, detail, receiptOrder);
        //订单数据同步
        orderPaySubmit(req, receiptOrder, detail, null);
        return;
    }

    /**
     * 申请余额变更
     *
     * @param req
     * @param receiptOrderDetail
     * @param receiptOrder
     */
    public void startBalanceItem(ReceiptOrderDetailReq req, ReceiptOrderDetail receiptOrderDetail, ReceiptOrder receiptOrder) {
        //线下转账申请记账cost--平台id+转账金额
        if (ObjectUtils.isNotEmpty(req.getPayAmount()) && req.getPayAmount().compareTo(BigDecimal.ZERO) > 0) {
            AccountBalance account = balanceService.getAccount(req.getPlatformAccountId());
            if (account == null) {
                throw new BusinessException(ACCOUNT_DATA_IS_NOT_EXISTS.getCode(),
                        ACCOUNT_DATA_IS_NOT_EXISTS.getMessage());
            }
            CostItemStaveParam cisp = CopyObjectUtils.copyAtoB(account, CostItemStaveParam.class);
            cisp.setAccountId(account.getId());
            cisp.setAmount(req.getPayAmount());
            cisp.setBusinessPayNo(receiptOrder.getPayNo());
            cisp.setBusinessId(receiptOrderDetail.getId());
            cisp.setBusinessNo(receiptOrder.getMainOrderNo());
            cisp.setBusinessOrderNo(receiptOrder.getOrderNo());
            cisp.setTypeEnums(CostTypeEnums.COST_ITEM_EXPEND.getCode());
            cisp.setPayWayEnums(CostWayEnums.COST_ITEM_OFFLINE_TRANSFER.getCode());
            costItemService.startCostItemStave(cisp);
        }
        //平台账户申请余额变更--平台id+平台支付金额
        if (ObjectUtils.isNotEmpty(req.getPlatformAmount()) && req.getPlatformAmount().compareTo(BigDecimal.ZERO) > 0) {
            AccountBalance account = balanceService.getAccount(req.getPlatformAccountId());
            if (account == null) {
                throw new BusinessException(ACCOUNT_DATA_IS_NOT_EXISTS.getCode(),
                        ACCOUNT_DATA_IS_NOT_EXISTS.getMessage());
            }
            BalanceItemStaveParam bisp = CopyObjectUtils.copyAtoB(account, BalanceItemStaveParam.class);
            bisp.setAccountId(account.getId());
            bisp.setUserId(req.getMemberId());
            bisp.setAmount(req.getPlatformAmount());
            bisp.setBusinessPayNo(receiptOrder.getPayNo());
            bisp.setBusinessId(receiptOrderDetail.getId());
            bisp.setBusinessNo(receiptOrder.getMainOrderNo());
            bisp.setBusinessOrderNo(receiptOrder.getOrderNo());
            bisp.setTypeEnums(CostTypeEnums.COST_ITEM_EXPEND.getCode());
            bisp.setPayWayEnums(CostWayEnums.COST_ITEM_WALLET.getCode());
            bisp.setDirectionEnums(BalanceDirectionEnums.BALANCE_SUB.getCode());
            balanceItemService.startBalanceItem(bisp);
        }
        //定向账户申请余额变更--定向账户id+定向支付金额
        if (ObjectUtils.isNotEmpty(req.getDirectAmount()) && req.getDirectAmount().compareTo(BigDecimal.ZERO) > 0) {
            AccountBalance account = balanceService.getAccount(req.getDirectAccountId());
            if (account == null) {
                throw new BusinessException(ACCOUNT_DATA_IS_NOT_EXISTS.getCode(),
                        ACCOUNT_DATA_IS_NOT_EXISTS.getMessage());
            }
            BalanceItemStaveParam bisp = CopyObjectUtils.copyAtoB(account, BalanceItemStaveParam.class);
            bisp.setAccountId(account.getId());
            bisp.setUserId(req.getMemberId());
            bisp.setAmount(req.getDirectAmount());
            bisp.setBusinessPayNo(receiptOrder.getPayNo());
            bisp.setBusinessId(receiptOrderDetail.getId());
            bisp.setBusinessNo(receiptOrder.getMainOrderNo());
            bisp.setBusinessOrderNo(receiptOrder.getOrderNo());
            bisp.setTypeEnums(CostTypeEnums.COST_ITEM_EXPEND.getCode());
            bisp.setPayWayEnums(CostWayEnums.COST_ITEM_WALLET.getCode());
            bisp.setDirectionEnums(BalanceDirectionEnums.BALANCE_SUB.getCode());
            balanceItemService.startBalanceItem(bisp);
        }
    }

    /**
     * 确定支付-提交订单信息
     *
     * @param rodReq
     * @return
     */
    public String orderPaySubmit(ReceiptOrderDetailReq rodReq, ReceiptOrder ro, ReceiptOrderDetail rod, Integer creditStatus) {

        /**
         * orderPayWay全额赊销支付时可以不传，如果时已支付部分本金要
         * 支付方式：1-线下支付 2-现金账户 3-组合支付 4-微信支付 5-通联支付 6-支付宝支付
         */
        //存在未付利息和未付违约金的要去支付
        List<ReceiptOrderDetail> details = receiptOrderDetailManager.list(new LambdaQueryWrapper<ReceiptOrderDetail>()
                .eq(ReceiptOrderDetail::getReceiptId, ro.getId())
                .eq(ReceiptOrderDetail::getIsDeleted, false)
                .eq(ReceiptOrderDetail::getIsCancel, false)
        );
        //未付部分
        BigDecimal upBreak = details.stream().map(ReceiptOrderDetail::getUnPayBreak).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal upInterest = details.stream().map(ReceiptOrderDetail::getUnPayInterest).reduce(BigDecimal.ZERO, BigDecimal::add);
        Integer orderPayWay = null;
        boolean isCreditPay = false;
        boolean isNeedConfim = false;
        BigDecimal submitAmount = BigDecimal.ZERO;
        String payMode = rodReq.getPayMode();
        BigDecimal payment = rodReq.getBalancePayAmount().add(rodReq.getPayAmount());
        BigDecimal breakAmount = rod.getBreakAmount();
        BigDecimal interestAmount = rod.getInterestAmount();
        if (rod.getFundsAmount().compareTo(payment) > 0) {
            breakAmount = BigDecimal.ZERO;
            interestAmount = BigDecimal.ZERO;
        } else {
            breakAmount = breakAmount.add(upBreak);
            interestAmount = interestAmount.add(upInterest);
        }
        //赊销模式
        if (ReceiptOrderPayModeEnum.CREDIT.getCode().equalsIgnoreCase(payMode)) {
            isCreditPay = true;
            if (null != rodReq.getPayAmount() && rodReq.getPayAmount().compareTo(BigDecimal.ZERO) > 0) {
                orderPayWay = OrderNeedPayWayEnums.OFFLINE_TRANSFER.getCode();
                submitAmount = rodReq.getPayAmount();
                isNeedConfim = true;
            }
            if (null != rodReq.getBalancePayAmount() && rodReq.getBalancePayAmount().compareTo(BigDecimal.ZERO) > 0) {
                orderPayWay = OrderNeedPayWayEnums.WALLET.getCode();
                submitAmount = rodReq.getBalancePayAmount();
                isNeedConfim = true;
            }
        }
        //线下转账模式
        if (ReceiptOrderPayModeEnum.OFFLINE_TRANSFER.getCode().equalsIgnoreCase(payMode)) {
            orderPayWay = OrderNeedPayWayEnums.OFFLINE_TRANSFER.getCode();
            isNeedConfim = true;
        }
        //余额模式
        if (ReceiptOrderPayModeEnum.WALLET.getCode().equalsIgnoreCase(payMode)) {
            orderPayWay = OrderNeedPayWayEnums.WALLET.getCode();
            isNeedConfim = true;
        }
        //组合模式
        if (ReceiptOrderPayModeEnum.GROUP.getCode().equalsIgnoreCase(payMode)) {
            orderPayWay = OrderNeedPayWayEnums.GROUP.getCode();
            isNeedConfim = true;
        }
        //赊销状态 1-正常赊销 2-违约赊销
        Integer orderNeedCreditStatus = null;
        if (ReceiptCreditStatusEnums.BREAK_CREDIT.getCode().equals(creditStatus)) {
            orderNeedCreditStatus = OrderNeedCreditStatusEnums.BREAK_CREDIT.getCode();
        } else if (ReceiptCreditStatusEnums.NORMAL_CREDIT.getCode().equals(creditStatus)) {
            orderNeedCreditStatus = OrderNeedCreditStatusEnums.NORMAL_CREDIT.getCode();
        }
        PaySubmitReq paySubmitReq = new PaySubmitReq();
        paySubmitReq.setPayNo(ro.getPayNo());
        paySubmitReq.setCreditIsPayedAmount(submitAmount);
        paySubmitReq.setIsCreditPay(isCreditPay);
        paySubmitReq.setIsNeedConfirm(isNeedConfim);
        paySubmitReq.setPayWay(orderPayWay);
        paySubmitReq.setPayTime(LocalDateTime.now());
        paySubmitReq.setCreditStatus(orderNeedCreditStatus);
        paySubmitReq.setPayMember(rodReq.getMemberId());
        paySubmitReq.setBreakAmount(breakAmount);
        paySubmitReq.setInterestAmount(interestAmount);
        paySubmitReq.setPartPayAmount(rod.getReceiveAmount());
        paySubmitReq.setReceiptOrderDetailId(rod.getId().intValue());
        Integer part = 0;
        if (BigDecimalUtils.amountScale(rod.getReceiveAmount()).compareTo(BigDecimalUtils.amountScale(ro.getShouldAmount())) < 0
                && orderNeedCreditStatus == null) {
            part = 1;
        }
        paySubmitReq.setIsPartPay(part);
        Long startTime = System.currentTimeMillis();
        log.info("确定支付orderPaySubmit-请求参数:{}", JSON.toJSONString(paySubmitReq));
        Result<OrderPayResp> result = iPayFeign.orderPaySubmit(paySubmitReq);

        Long endTime = System.currentTimeMillis();
        Long tempTime = (endTime - startTime);
        log.info("确定支付orderPaySubmit响应-payNo:{},耗时:{} ms, Result:{}", ro.getPayNo(), tempTime, result);

        if (0 != result.getCode()) {
            throw new BusinessException(CommonResultCode.CommonResultEnum.SYSTEM_EXCEPTION.getCode(), result.getMessage());
        }
        OrderPayResp orderPayResp = result.getData();
        return orderPayResp.getPayNo();
    }
}
